我编写了一项服务,可下载图像,通过zip存档将其加入并上传回aws。此服务应省时。 我的第一个version很简单:
但是我认为所有从磁盘操作进行保存和读取的性能都比内存通信低。
我joined一起下载和存档(所有下载阅读器直接进入存档器)。但是我不明白如何与上传者一起加入。
S3上传者需要 ReadSeeker 来放置对象。存档器的当前实现是:
func Archive(inputQueue <-chan Input) io.ReadSeeker {
zipFile, err := os.Create("test_arch.zip")
if log.Error(err) {
os.Exit(1)
}
arch := zip.NewWriter(zipFile)
go func() {
defer arch.Close()
for input := range inputQueue {
header := &zip.FileHeader{
Name: filepath.Join(baseDir, input.Path()),
Method: zip.Store,
}
writer, err := arch.CreateHeader(header)
if log.Error(err){
os.Exit(1)
}
_, err = io.Copy(writer, input.Reader())
}
}()
return zipFile
}
它将存档保存到磁盘。 如何将存档写入中间结构以将该结构传递给require一个 ReadSeeker 的s3上传器?
答案 0 :(得分:2)
如果可能,您应该使用"github.com/aws/aws-sdk-go/service/s3/s3manager"
软件包中的s3manager.Uploader.Upload
,该软件包接受io.Reader
的输入并为您处理所有分段上传逻辑(这就是{{1} }接口)。
如果不是这样,则可以将io.Seeker
用作bytes.Buffer
而不是文件,然后将io.Writer
用作bytes.Reader
。
例如
io.ReadSeeker
然后将缓冲区字节包装在func Archive(inputQueue <-chan Input) *bytes.Buffer {
buf := bytes.NewBuffer(nil)
arch := zip.NewWriter(buf)
go func() {
defer arch.Close()
for input := range inputQueue {
header := &zip.FileHeader{
Name: filepath.Join(baseDir, input.Path()),
Method: zip.Store,
}
writer, err := arch.CreateHeader(header)
if log.Error(err) {
os.Exit(1)
}
_, err = io.Copy(writer, input.Reader())
}
}()
return buf
}
中:
bytes.Reader
答案 1 :(得分:0)
由于s3manager可以上传常规的io.Reader,所以我没有使用文件,而是使用了 Pipe ,如下所示:
const baseDir = "export"
func Archive(inputQueue <-chan Input) io.Reader {
pr, pw := io.Pipe()
arch := zip.NewWriter(pw)
go func() {
defer pw.Close()
defer arch.Close()
for input := range inputQueue {
header := &zip.FileHeader{
Name: filepath.Join(baseDir, input.Path()),
Method: zip.Store,
}
writer, err := arch.CreateHeader(header)
if log.Error(err) {
os.Exit(1)
}
_, err = io.Copy(writer, input.Reader())
}
fmt.Println()
}()
return pr
}
读取进入下一级的管道的一半(服务的上载部分)。将一半的管道写到当前级别(服务的归档部分)。 根据管道的性质,它可以使用少量的内存来处理大量的存档。而且此解决方案是线程安全的。