【问题标题】:Stream only partially read when downloading object from Amazon AWS S3 [duplicate]从 Amazon AWS S3 下载对象时,流仅部分读取 [重复]
【发布时间】:2019-02-12 01:36:43
【问题描述】:

我正在尝试使用 C# 从我的存储桶中简单地下载一个对象,就像我们在 S3 示例中可以找到的那样,我无法弄清楚为什么流不会完全复制到我的字节数组中。只复制前 8192 个字节,而不是整个流。

我尝试过使用Amazon.S3.AmazonS3ClientAmazon.S3.Transfer.TransferUtility,但在这两种情况下,实际上只有第一个字节被复制到缓冲区中。

var stream = await _transferUtility.OpenStreamAsync(BucketName, key);
using (stream)
{
    byte[] content = new byte[stream.Length];
    stream.Read(content, 0, content.Length);
    // Here content should contain all the data from the stream, but only the first 8192 bytes are actually populated.
}

调试的时候看到流类型是Amazon.Runtime.Internal.Util.Md5Stream,而流里面,在调用Read()之前属性CurrentPosition=0。调用之后CurrentPosition变成了8192,好像确实只表示读取了前 8K 的数据。流的总Length是104042。

如果我对stream.Read() 进行更多调用,我会看到更多数据被读取并且CurrentPosition 的价值会增加。但是CurrentPosition 不是公共属性,我无法在我的代码中访问它来创建while() 循环(并且必须编写这样的循环来读取所有数据似乎有点笨拙)。

为什么我的代码中只读取了前 8K?我应该如何继续阅读整个流?

我尝试拨打stream.Flush(),但没有解决问题。

编辑 1

我已经修改了我的代码,所以它执行以下操作:

var stream = await _transferUtility.OpenStreamAsync(BucketName, key);
using (stream)
{
    byte[] content = new byte[stream.Length];
    var bytesRead = 0;

    while (bytesRead < stream.Length)
        bytesRead += stream.Read(content, bytesRead, content.Length - bytesRead);
}

而且它有效。但是看起来还是很笨重。我必须这样做正常吗?

编辑 2

最终的解决方案是创建一个正确大小的 MemoryStream,然后调用CopyTo()。因此,如果Read() 在读取整个流之前开始返回 0,则不再有笨重的循环,也没有无限循环的风险:

var stream = await _transferUtility.OpenStreamAsync(BucketName, key);
using (stream)
{
    using (var memoryStream = new MemoryStream((int)stream.Length))
    {
        stream.CopyTo(memoryStream);
        var myBuffer = memoryStream.GetBuffer();
    }
}

【问题讨论】:

  • 不要忽略stream.Read的返回值。链接的骗子会看到你很好。
  • 是的,使用stream.Read时循环是正常的。您可以创建一个MemoryStream(如果您可以提前获得内容长度,则可能是所需的大小)然后只需stream.CopyTo(myMemoryStream)
  • 对于每个调用,您都将覆盖内容缓冲区。您需要在缓冲区中包含起始位置。
  • 您还需要处理返回字节为 0 的情况,否则您的代码将永远循环出错。
  • @JohnHanley 仔细看,Read() 的第二个参数是bytesRead。所以每次读取总是使用正确的偏移量,没有覆盖。

标签: c# amazon-web-services amazon-s3 aws-sdk


【解决方案1】:

stream.Read() 返回读取的字节数。然后,您可以跟踪读取的总字节数,直到到达文件末尾 (content.Length)。

您也可以循环直到返回值为 0,意思是 error / no more bytes left

您需要跟踪内容缓冲区的当前偏移量,以免每次调用都覆盖数据。

【讨论】:

    猜你喜欢
    • 2012-06-17
    • 2018-03-14
    • 2013-07-29
    • 2018-01-09
    • 2013-03-29
    • 2019-07-16
    • 1970-01-01
    • 2017-06-27
    • 1970-01-01
    相关资源
    最近更新 更多