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或乱码。”或“一行”,而是读一个7位编码的长度前缀(变长整数),再读对应字节数的UTF-8内容。如果文件不是用
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()当通用字符串读取器——它和写入端强绑定,换种方式写进去,就读不出来。
