我需要实现一个从AWS S3下载大文件的功能。我尝试查看许多示例以及 AWS 文档并提出了这个解决方案:
func (b *biz) S3DownloadFile(ctx context.Context, key string) ([]byte, error) {
downloader := manager.NewDownloader(b.s3client, func(d *manager.Downloader) {
d.PartSize = 5 * 1024 * 1024 // 5MB parts
})
buffer := manager.NewWriteAtBuffer([]byte{})
_, err := downloader.Download(ctx, buffer, &s3.GetObjectInput{
Bucket: &b.bucketName,
Key: &key,
})
if err != nil {
log.Printf("Error downloading file: %v", err)
return nil, err
}
return buffer.Bytes(), err
}
然后在客户端,我只需获取此 API 并创建一个不可见的
a
标签,然后自动单击它即可下载文件。
问题
对于大文件,似乎这种方法将所有块下载到内存中,然后将整个 [] 字节切片发送到客户端。这使得客户不得不永远等待。
目标
我的目标是复制预签名 url 当前正在执行的操作,当单击预签名 url 时,文件将作为流下载到客户端,因此用户知道该文件正在下载。
我的发现
目前,我正在考虑2个解决方案:
除了我的解决方案之外,还有其他更好的方法来处理这个问题吗?谢谢
我不知道你使用的是哪个模块,但是如果你使用aws sdk,你可以像这样得到
io.ReadCloser
。
我认为这将允许您以块的形式实现所需的操作,而无需一次将其全部移动到内存中。
import (
"io"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)
var sess = session.Must(session.NewSession())
func NewS3Reader(bucket, key string) (io.ReadCloser, error) {
objOut, err := s3.New(sess).GetObject(&s3.GetObjectInput{Bucket: &bucket, Key: &key})
if err != nil {
return nil, err
}
return objOut.Body, nil
}