使用C#从Amazon S3流式传输文件,具有寻求可能性

4

我需要在亚马逊S3上处理大文件。 我该如何从S3获取大文件的一部分? 最好的方法是获取带有寻址功能的流。 不幸的是,response.ResponseStreamCanSeek属性为false:

GetObjectRequest request = new GetObjectRequest();
request.BucketName = BUCKET_NAME;
request.Key = NumIdToAmazonKey(numID);
GetObjectResponse response = client.GetObject(request);

你有什么具体的问题? - MeanGreen
4个回答

6
您可以按照以下步骤读取文件的特定部分:
GetObjectRequest request = new GetObjectRequest 
{
    BucketName = bucketName,
    Key = keyName,
    ByteRange = new ByteRange(0, 10)
};

请查看文档

2
我知道这不完全是OP所要求的,但我需要一个可寻址的s3流,以便在不下载它们的情况下读取Parquet文件,所以我在这里尝试了一下:https://github.com/mukunku/RandomHelpers/blob/master/SeekableS3Stream.cs 性能并不像我预期的那么糟糕。您可以使用TimeWastedSeeking属性查看允许在s3流上执行Seek()操作浪费了多少时间。
以下是如何使用它的示例:
using (var client = new AmazonS3Client(credentials, Amazon.RegionEndpoint.USEast1))
{
    using (var stream = SeekableS3Stream.OpenFile(client, "myBucket", "path/to/myfile.txt", true))
    {
        //stream is seekable!
    }
}

看起来很酷,但是较新的AWS客户端不支持非异步方法,而且Seek()没有SeekAsync()的对应方法,所以这段代码有点难以应用。 - undefined

1

1
看起来它所做的只是下载文件并使用MemoryStream将其加载到内存中。这对于处理巨大文件的OP问题不起作用。 - Sal

0

虽然对于原帖来说已经晚了,但我刚刚发布了一篇文章和代码演示,介绍了一个SeekableS3Stream,在实际使用中表现相当不错。

https://github.com/mlhpdx/seekable-s3-stream

具体来说,我演示了如何使用DiscUtils库读取一个大ISO磁盘映像中的单个小文件,而不需要进行修改,通过实现一个随机访问流,该流使用Range请求来按需拉取文件的部分,并将它们保留在MRU列表中,以防止重新下载文件中热数据结构的范围(例如zip中央目录记录)。
使用方法同样简单:
using System;
using System.IO;
using System.Threading.Tasks;
using Amazon.S3;
using DiscUtils.Iso9660;

namespace Seekable_S3_Stream
{
    class Program
    {
        const string BUCKET = "rds.nsrl.nist.gov";
        const string KEY = "RDS/current/RDS_ios.iso"; // "RDS/current/RDS_modern.iso";
        const string FILENAME = "READ_ME.TXT";
        static async Task Main(string[] args)
        {
            var s3 = new AmazonS3Client();

            using var stream = new Cppl.Utilities.AWS.SeekableS3Stream(s3, BUCKET, KEY, 1 * 1024 * 1024, 4);
            using var iso = new CDReader(stream, true);
            using var file = iso.OpenFile(FILENAME, FileMode.Open, FileAccess.Read);
            using var reader = new StreamReader(file);
            var content = await reader.ReadToEndAsync();

            await Console.Out.WriteLineAsync($"{stream.TotalRead / (float)stream.Length * 100}% read, {stream.TotalLoaded / (float)stream.Length * 100}% loaded");
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接