从 Amazon AWS S3 下载对象时流仅部分读取
Stream only partially read when downloading object from Amazon AWS S3
我正在尝试使用 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
不是 public 属性,我无法在我的代码中访问它来创建 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()
returns 读取的字节数。然后,您可以跟踪读取的字节总数,直到到达文件末尾 (content.Length
)。
您也可以只循环直到返回值为 0,这意味着 error
/ no more bytes left
。
您将需要跟踪内容缓冲区的当前偏移量,以免每次调用都覆盖数据。
我正在尝试使用 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
不是 public 属性,我无法在我的代码中访问它来创建 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()
returns 读取的字节数。然后,您可以跟踪读取的字节总数,直到到达文件末尾 (content.Length
)。
您也可以只循环直到返回值为 0,这意味着 error
/ no more bytes left
。
您将需要跟踪内容缓冲区的当前偏移量,以免每次调用都覆盖数据。