3 回答
TA貢獻1851條經驗 獲得超4個贊
當您將文件部分傳遞給multi.PutPart方法 (n, strings.NewReader ("")) 時,您的代碼必須更改一些點才能使其正常工作,下面的代碼將起作用。
記住 PutPart 發送分段上傳的一部分,從 r 讀取所有內容,除了最后一個部分,每個部分的大小必須至少為 5MB。 它在 goamz 文檔中有描述。
我已更改為正常工作的要點:
在這里,我使用文件的所有字節創建我們的 headerPart
HeaderPart: = strings.NewReader (string (bytes) )
這里io.ReadFull (HeaderPart, partBuffer)我正在讀取make ([] byte, partSize)命令的整個緩沖區部分,每次它都位于文件的某個部分。
當我們運行multi.PutPart (int (i) +1, strings.NewReader (string (partBuffer))) 時,我們必須+1,因為它不計算部分 0,而不是傳遞目標文件,我們將傳遞部分的內容使用strings.NewReader函數為此。
在下面查看您的代碼,它現在可以正常工作。
package main
import(
"bufio"
"fmt"
"math"
"net/http"
"os"
"launchpad.net/goamz/aws"
"launchpad.net/goamz/s3"
)
func check(err error) {
if err != nil {
panic(err)
}
}
func main() {
fmt.Println("Test")
auth := aws.Auth{
AccessKey: "xxxxxxxxxxx", // change this to yours
SecretKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
}
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...")
HeaderPart := strings.NewReader(string(bytes))
for i := uint64(0); i < totalPartsNum; i++ {
partSize := int(math.Min(fileChunk, float64(fileSize-int64(i*fileChunk))))
partBuffer := make([]byte, partSize)
n , errx := io.ReadFull(HeaderPart, partBuffer)
check(errx)
part, err := multi.PutPart(int(i)+1, strings.NewReader(string(partBuffer))) // 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(n))
parts = append(parts, part)
}
err = multi.Complete(parts)
check(err)
fmt.Println("\n\nPutPart upload completed")
}
TA貢獻1786條經驗 獲得超11個贊
您讀入的數據partBuffer根本沒有使用。您傳遞file到multi.PutPart并讀取全部內容的file,求它回到起點為必要吹你做的工作之外的所有。
你的代碼最小的變化將是通過bytes.NewReader(partBuffer)進入PutPart,而不是file。bytes.Reader實現需要的io.ReadSeeker接口PutPart,并將其大小報告為partBuffer.
另一種方法是使用io.SectionReader類型 - 而不是自己將數據讀入緩沖區,您只需SectionReader根據file您想要的大小和偏移量創建一系列s并將它們傳遞給PutPart,它們將傳遞讀取到底層文件閱讀器。這應該也能正常工作,并大大減少您必須編寫(和錯誤檢查)的代碼。它還避免了在 RAM 中不必要地緩沖整個數據塊。
TA貢獻1784條經驗 獲得超7個贊
這里的問題可能是由于沒有完全讀取文件造成的。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上找到更多文檔。
- 3 回答
- 0 關注
- 408 瀏覽
添加回答
舉報
