【发布时间】:2019-02-12 01:36:43
【问题描述】:
我正在尝试使用 C# 从我的存储桶中简单地下载一个对象,就像我们在 S3 示例中可以找到的那样,我无法弄清楚为什么流不会完全复制到我的字节数组中。只复制前 8192 个字节,而不是整个流。
我尝试过使用Amazon.S3.AmazonS3Client 和Amazon.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