当 BinaryReader 打开时,使用 Stream.Seek 是否安全?

本文关键字:Seek Stream 是否 安全 使用 BinaryReader | 更新日期: 2023-09-27 18:33:37

由于 BinaryReader 的底层缓冲策略,我不清楚是否可以读取存储在流中的偏移量,然后将流重新定位在此偏移量以恢复流。

例如,以下代码是否正常:

using (var reader = new CustomBinaryReader(inputStream))
{
   var offset= reader.ReadInt32();
   reader.BaseStream.Seek(offset, SeekOrigin.Begin);
   //Then resume reading the streaming
}

还是我应该在查找流之前关闭第一个二进制读取器,然后重新打开第二个读取器?

int offset;
using (var firstReader = new CustomBinaryReader(inputStream))
{
   offset= firstReader.ReadInt32();
}
inputStream.Seek(offset, SeekOrigin.Begin);
using (var secondReader = new CustomBinaryReader(inputStream))
{
   //Then resume reading the streaming
}

当 BinaryReader 打开时,使用 Stream.Seek 是否安全?

BinaryReader 确实使用缓冲区,但仅用于从基本流中读取足够的字节来转换值。 换句话说,ReadInt32() 将首先缓冲 4 个字节,ReadDecimal() 将首先缓冲 16 个字节,依此类推。 ReadString() 是比较棘手的方法,但它也有对策,字符串由 BinaryWriter 在文件中编码,它首先写入字符串长度。 这样 BinaryReader 就可以确切地知道在转换字符串之前要缓冲多少字节。

因此,在其中一个 ReadXxx() 方法返回后,缓冲区始终为空,并且在 BaseStream 上调用 Seek() 就可以了。 这也是Microsoft不需要覆盖 Seek() 方法的原因。

MSDN 文章中的警告说明是合适的,如果您在 Seek() 调用后调用 ReadXxx() 方法,您肯定会多次阅读该"偏移"值。 然而,我认为这完全是故意的。

我会说它并不总是安全的(尽管在某些情况下可能是安全的)。

BinaryReader.BaseStream 的Microsoft文档明确指出:

在读取或使用二进制读取器时使用基础流可能会导致数据丢失和损坏。例如,相同的字节可能会被多次读取,字节可能会被跳过,或者字符读取可能变得不可预测。

所以我会避免它。

(有趣的是,有一个BinaryWriter.Seek()方法,但没有BinaryReader.Seek()

根据我的经验,只要您同时使用它们并且没有其他线程对流执行任何操作,那么它就可以正常工作。

我在编写的应用程序中广泛使用二进制文件格式,并且从未遇到过问题。