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 关注
- 334 浏览
添加回答
举报