4

Mitchell Hashimoto による goamz フォークによって提供される PutPart メソッドを使用しようとしています。悲しいことに、パーツを取り戻してサイズを確認するたびに、それは単なるチャンクではなく、ファイル全体のサイズであると考えているようです。

例えば

15m のファイルをアップロードすると、

Uploading...
Processing 1 part of 3 and uploaded 5242880.0 bytes.
 Processing 2 part of 3 and uploaded 5242880.0 bytes.
 Processing 3 part of 3 and uploaded 5242880.0 bytes.

代わりに、次のように表示されます。

Uploading...
Processing 1 part of 3 and uploaded 15728640 bytes.
 Processing 2 part of 3 and uploaded 15728640 bytes.
 Processing 3 part of 3 and uploaded 15728640 bytes.

これは file.Read(partBuffer) の問題によるものですか? どんな助けでも大歓迎です。

Macでgo 1.5.1を使用しています。

package main

import (
    "bufio"
    "fmt"
    "math"
    "net/http"
    "os"

    "github.com/mitchellh/goamz/aws"
    "github.com/mitchellh/goamz/s3"
)

func check(err error) {
    if err != nil {
        panic(err)
    }
}

func main() {
    fmt.Println("Test")

    auth, err := aws.GetAuth("XXXXX", "XXXXXXXXXX")
    check(err)

    client := s3.New(auth, aws.USWest2)

    b := s3.Bucket{
        S3:   client,
        Name: "some-bucket",
    }

    fileToBeUploaded := "testfile"
    file, err := os.Open(fileToBeUploaded)
    check(err)
    defer file.Close()

    fileInfo, _ := file.Stat()
    fileSize := fileInfo.Size()
    bytes := make([]byte, fileSize)

    // read into buffer
    buffer := bufio.NewReader(file)
    _, err = buffer.Read(bytes)
    check(err)
    filetype := http.DetectContentType(bytes)

    // set up for multipart upload
    multi, err := b.InitMulti("/"+fileToBeUploaded, filetype, s3.ACL("bucket-owner-read"))
    check(err)

    const fileChunk = 5242880 // 5MB
    totalPartsNum := uint64(math.Ceil(float64(fileSize) / float64(fileChunk)))
    parts := []s3.Part{}

    fmt.Println("Uploading...")
    for i := uint64(1); i < totalPartsNum; i++ {

        partSize := int(math.Min(fileChunk, float64(fileSize-int64(i*fileChunk))))
        partBuffer := make([]byte, partSize)

        _, err := file.Read(partBuffer)
        check(err)

        part, err := multi.PutPart(int(i), file) // write to S3 bucket part by part
        check(err)

        fmt.Printf("Processing %d part of %d and uploaded %d bytes.\n ", int(i), int(totalPartsNum), int(part.Size))
        parts = append(parts, part)
    }

    err = multi.Complete(parts)
    check(err)

    fmt.Println("\n\nPutPart upload completed")

}
4

3 に答える 3

0

この問題は、ファイルを完全に読み取っていないことが原因である可能性があります。Read少し微妙かもしれません:

Read は、最大 len(p) バイトを p に読み込みます。読み取ったバイト数 (0 <= n <= len(p)) と発生したエラーを返します。Read が n < len(p) を返したとしても、呼び出し中にすべての p をスクラッチ スペースとして使用する場合があります。一部のデータが利用可能であり、len(p) バイトではない場合、Read は通常、それ以上待つのではなく、利用可能なものを返します。

したがって、おそらくioReadFullor (better)を使用する必要がありますio.CopyN

そうは言っても、公式の AWS Go パッケージに切り替えてみるべきだと思います。彼らはあなたのためにこれらすべてを処理する便利なアップローダーを持っています:

package main

import (
    "log"
    "os"

    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/s3/s3manager"
)

func main() {
    bucketName := "test-bucket"
    keyName := "test-key"
    file, err := os.Open("example")
    if err != nil {
        log.Fatalln(err)
    }
    defer file.Close()

    sess := session.New()
    uploader := s3manager.NewUploader(sess)

    // Perform an upload.
    result, err := uploader.Upload(&s3manager.UploadInput{
        Bucket: &bucketName,
        Key:    &keyName,
        Body:   file,
    })
    if err != nil {
        log.Fatalln(err)
    }
    log.Println(result)
}

godoc.orgでさらに多くのドキュメントを見つけることができます。

于 2016-01-13T03:36:40.900 に答える
0

読み込んだデータpartBufferはまったく使用されません。に渡すと、 の内容全体が読み取らfileれ、必要に応じて先頭に戻り、行ったすべての作業が吹き飛ばされます。multi.PutPartfile

コードへの最小限の変更は、 の代わりにに渡すbytes.NewReader(partBuffer)ことです。必要なインターフェースを実装し、そのサイズを のサイズとして報告します。PutPartfilebytes.Readerio.ReadSeekerPutPartpartBuffer

別の方法として、 io.SectionReaderタイプを使用することもできます— 自分でデータをバッファに読み込む代わりに、必要なサイズとオフセットにSectionReader基づいて一連の を作成し、それらを に渡すだけで、読み取りが渡されます基礎となるファイルリーダーに。これでも同様に機能し、記述 (およびエラー チェック) が必要なコードを大幅に削減できます。また、データのチャンク全体を RAM に不必要にバッファリングすることも回避します。filePutPart

于 2016-01-13T03:45:47.803 に答える