binarywriter写入需调用flush()或close()确保落盘,推荐using自动释放;binaryreader.readstring()依赖binarywriter写入的长度前缀和utf-8编码;结构体须逐字段手动序列化;eof判断应依赖长度头而非peekchar()或position比较。

BinaryWriter写入二进制文件时,必须手动调用Flush()或Close()才能确保数据落盘
很多人写完Write()就以为文件已保存,结果打开全是空的或缺尾部数据。这是因为BinaryWriter内部有缓冲区,默认不会每写一次就刷到磁盘。
- 推荐用
using语句自动释放和刷新:using (var fs = new FileStream("data.bin", FileMode.Create)) using (var writer = new BinaryWriter(fs)) { writer.Write(42); writer.Write("hello"); } // Close() 和 Flush() 在这里自动触发 - 如果不用
using,务必在最后调用writer.Close()(Dispose()也行),Flush()只清缓冲区,不关闭流 - 直接写
fs.Write()绕过BinaryWriter?可以,但会丢失类型编码逻辑(比如string自动写长度前缀)
BinaryReader读取时,ReadString()依赖UTF-8编码且要求前缀长度,不是原始字节读取
BinaryReader.ReadString()不是读“直到
BinaryReader.ReadString()不是读“直到\0”或“一行”,而是读一个7位编码的长度前缀(变长整数),再读对应字节数的UTF-8内容。如果文件不是用BinaryWriter.WriteString()写的,大概率抛EndOfStreamException或乱码。
BinaryWriter.WriteString()写的,大概率抛EndOfStreamException或乱码。
- 确认写入端:只有
BinaryWriter.WriteString()写的数据,才能用BinaryReader.ReadString()安全读 - 想读裸字节?改用
reader.ReadBytes(n)或reader.ReadChar()等基础方法 - 编码不匹配?
BinaryReader构造时可传Encoding,但ReadString()仍按自己的格式解析长度——编码只影响后续UTF-8解码
结构体序列化不能直接用BinaryWriter,需手动拆解字段
BinaryWriter没有Write(MyStruct)重载。它不理解结构体布局、字段顺序、对齐或[MarshalAs],直接Marshal.Copy又容易踩平台差异(比如bool占1字节还是4字节)。
- 安全做法:逐字段写,控制顺序和大小
writer.Write(point.X); // double writer.Write(point.Y); // double writer.Write(point.IsActive); // bool → 写为 byte 0/1 更可控
- 需要紧凑二进制?考虑
Span<byte></byte>+Unsafe.As<t byte></t>(.NET Core 3+),但得确保struct是blittable且无引用类型 - 跨语言交互?别依赖
BinaryWriter默认行为——它不保证与C/C++结构体二进制兼容
文件末尾判断别用PeekChar(),BinaryReader没有可靠的EOF探测方法
PeekChar()在二进制流上意义不大(它尝试按当前编码读字符,可能失败或误判);BaseStream.Position == BaseStream.Length看似合理,但在网络流或压缩流中不可靠。
- 正确做法:明确知道要读多少项,或用长度头控制
// 写入时先写元素数量 writer.Write(items.Count); foreach (var item in items) { ... } // 读取时先读数量,再循环 int count = reader.ReadInt32(); for (int i = 0; i < count; i++) { ... } - 真要试探读?捕获
EndOfStreamException,但仅适用于“尽力而为”场景,不能作为主控逻辑 - 注意:
ReadByte()返回-1表示EOF,但ReadInt32()等直接抛异常,行为不统一
ReadString()当通用字符串读取器——它和写入端强绑定,换种方式写进去,就读不出来。










