C# - Stream.Read 偏移工作不正确
Posted
技术标签:
【中文标题】C# - Stream.Read 偏移工作不正确【英文标题】:C# - Stream.Read offset is working incorrectly 【发布时间】:2021-09-02 06:26:56 【问题描述】:我有一个如下所示的测试代码。我正在从流中读取,偏移 2 个位置,然后获取下一个 2 个字节。我希望结果是一个包含 2 个元素的数组。但这不起作用 - 偏移量被完全忽略,并且始终返回完整大小的数组,只有偏移量块具有值。 但这意味着我的结果表仍然很大,它只是有很多不需要的零
如何修改下面的代码,以便当长度 = 2 且偏移量 = 2 时 file.Read() 只返回 2 个字节的数组而不是 10 个?在现实世界的场景中,我正在处理大文件(> 2gigs),因此过滤掉结果数组不是一种选择。
编辑:由于问题尚不清楚 - 下面的代码要求我始终定义与流大小相同的输出数组。相反,我希望有一个大小为length
的输出(在下面的示例中,我希望有var buffer = new byte[2]
,但这会引发异常,因为 file.Read 忽略偏移量和长度并始终返回 10 个元素(使用仅读取其中 2 个,其余为虚拟零)。
private byte[] GetFilePart(int length, int offset)
//build some dummy content
var content = new byte[10];
for (int i = 0; i<10; i++)
content[i] = 1;
//read the data from content
var buffer = new byte[10];
using (Stream file = new MemoryStream(content))
file.Read(buffer, offset, length);
return buffer;
【问题讨论】:
我没有听懂你的问题——截图看起来是正确的。它从流中读取 2 个字节,并将它们写入buffer
中的偏移量 2(因此写入 buffer
中的索引 2 和 3)。你预计会发生什么?
指定你想要的尺寸? new byte[length];
Stream.Read
不会创建新数组,它会填充您传递的数组。因此,如果您希望结果数组的大小为 2,则需要传递一个大小为 2 的数组。另外,check the documentation
@canton7 我想定义 var buffer = new byte[2]。但随后代码失败,因为它试图始终填充 10 个元素。
@ojek 我不这么认为——如果length
是 2,它总是会读取 2 个字节。如果您有一个 2 字节的缓冲区,并尝试将 2 个字节读入其中,偏移 2(即写入缓冲区中的索引 2 和 3),那么这当然会失败:您需要一个 4 字节的缓冲区能够写入该缓冲区的索引 2 和 3:这是常识。我认为混淆可能是offset
是您想要开始写入的buffer
的偏移量,而不是您想要开始读取的file
中的偏移量。正如文档所说,“缓冲区中开始存储数据的从零开始的字节偏移量”
【参考方案1】:
看起来它对我来说工作正常;如果您使用以下内容初始化内容数组,也许您的困惑会有所消除:
for (int i = 1; i<=10; i++)
content[i-1] = i;
然后每个字节将有不同的数字,图像将如下所示:
offset
与buffer
的位置有关,Stream
将写入字节(它从content
的开头读取)。它与从content
中读取的字节无关。
想象Read
被称为WriteBytesInto(byte[] whatBuffer, int whereToStartWriting, int howManyBytesToWrite)
- 你提供它将写入的缓冲区并告诉它从哪里开始以及要执行多少操作
如果您这样做,已将 content
初始化为递增数字:
file.Read(buffer, 2, 3); //read 3 bytes from stream and write to buffer @ index 2
file.Read(buffer, 0, 2); //read 2 bytes from stream and write to buffer @ index 0
你的缓冲区最终看起来像:
4,5,1,2,3,0,0,0,0,0
1,2,3
先写,然后4,5
写下一个
如果您想从流中跳过两个字节(即从流中读取content
、Seek()
的第 3 和第 4 字节或设置其Position
(或者如 canton7 在评论中建议的那样,如果流是不可搜索,读取并丢弃一些字节)
我如何修改下面的代码,以便当长度 = 2 和偏移量 = 2 时 file.Read() 只返回一个 2 字节而不是 10 字节的数组?
好吧,file.Read
根本不返回数组;它会修改你给它的数组。如果你想要一个 2 字节数组,给它一个 2 字节数组:
byte buf = new byte[2];
file.Read(buf, 0, buf.Length);
如果要打开文件,请跳过前 7 个字节,然后将第 8 和第 9 字节读取到长度为 2 字节的数组中:
byte buf = new byte[2];
file.Position = 7; //absolute skip to 8th byte
file.Read(buf, 0, buf.Length);
有关在流中搜索的更多信息,请参阅Stream.Seek(0, SeekOrigin.Begin) or Position = 0
【讨论】:
(请注意,并非所有流都可以搜索,请检查Stream.CanSeek
。如果流不可搜索,您只需读取并丢弃任何要跳过的字节)
是的,虽然可以寻找 MemoryStream :)
可以,但他们也说这是“虚拟内容”,所以我不想对他们的实际用例做任何假设!
此外,OP 混淆看起来与buffer
大小有关。您可以编辑您的答案以解决 Stream.Read
不创建新数组,而是填充您传递给它的数组这一事实。所以,如果 OP 想要一个大小为 2 的缓冲区,他们必须这样做 var buffer = new byte[2];
谢谢!您的评论“偏移量与 Stream 将字节写入缓冲区的位置有关(它从内容的开头读取)。它与从内容中读取的字节无关”很好地解释了我的困惑。我在想偏移量是针对流源的,你是对的,它是针对输出缓冲区的,现在一切都说得通了,感谢您的澄清!以上是关于C# - Stream.Read 偏移工作不正确的主要内容,如果未能解决你的问题,请参考以下文章
如果没有发送任何内容,Stream.Read不会返回任何内容