内存中的ReadSeeker

时间:2018-08-18 11:52:56

标签: go

我编写了一项服务,可下载图像,通过zip存档将其加入并上传回aws。此服务应省时。 我的第一个version很简单:

  1. 并行下载所有文件并保存到磁盘。
  2. 从磁盘读取所有文件,通过zip包将其加入并保存回磁盘
  3. 从磁盘读取存档,并将其发送到s3。

但是我认为所有从磁盘操作进行保存和读取的性能都比内存通信低。

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上传器?

2 个答案:

答案 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
}

读取进入下一级的管道的一半(服务的上载部分)。将一半的管道写到当前级别(服务的归档部分)。 根据管道的性质,它可以使用少量的内存来处理大量的存档。而且此解决方案是线程安全的。