BinaryReader/BinaryWriter最稳妥但需注意字符串前缀和小端序;直接操作Stream可精确控制字节布局;Span+BinaryPrimitives适合高性能解析;格式定义必须与协议严格对齐。

用 BinaryReader 和 BinaryWriter 读写结构化二进制数据最稳妥
这两个类专为 .NET 的二进制序列化设计,自动处理字节序、类型长度和基础编码,比直接操作 Stream 更少出错。适用于保存/加载自定义结构体、数值数组、字符串(需注意编码)等。
常见错误:用 BinaryWriter.Write(string) 写入后,用 BinaryReader.ReadString() 读取失败——因为后者依赖前缀长度(UTF-8 编码的 7 位变长整数),若文件非它所写,会抛 EndOfStreamException 或乱码。
- 写字符串时,如需兼容性更强,改用
Write(byte[])+Encoding.UTF8.GetBytes() - 读数值类型(
int、double等)完全安全,它们按小端序固定长度写入 - 不要跨平台共享
BinaryReader写出的文件——.NET 不保证其他语言能解析其字符串格式或类型标识
直接用 Stream.Read / Stream.Write 控制每个字节
当你需要精确控制布局(比如对接 C/C++ 结构体、网络协议头、图像 raw 数据),必须绕过高层封装,直接操作字节数组。
典型场景:读取 BMP 文件头(14 字节固定结构)、拼接加密后的字节块、解析自定义二进制协议包。
- 务必检查返回值:
Read()可能只读到部分字节,需循环直到填满缓冲区或遇到 EOF - 写入前确认
Stream.CanWrite且已定位到正确位置(Position可写) - 使用
MemoryStream做中间缓存时,记得调用ToArray()获取真实字节,而非GetBuffer()(后者可能含未使用填充)
Span + BinaryPrimitives 是高性能二进制解析新方案
.NET Core 2.1+ 引入了零分配的二进制解析方式,适合高频、大数据量场景(如日志解析、实时传感器数据流)。
它不依赖流对象,直接在内存切片上解析整数、浮点数,避免了 BinaryReader 的内部缓冲和装箱开销。
- 读取小端整数:
BinaryPrimitives.ReadInt32LittleEndian(data),data是Span - 写入需手动复制:
BinaryPrimitives.WriteInt32LittleEndian(buffer, value) - 不处理字符串、变长字段,所有偏移和长度都得自己算清楚——错一位就全盘错解
文件打开模式和编码陷阱必须显式指定
二进制操作最常被忽略的是 FileStream 构造参数。默认 FileMode.Open + FileAccess.Read 只读,想写必须显式设 FileAccess.ReadWrite;追加写要用 FileMode.Append 并确保光标在末尾。
另一个坑是文本编码混入:哪怕你只读字节,如果用 StreamReader 打开二进制文件,它会尝试按 UTF-8 解码,遇到非法字节直接抛异常。
- 永远用
new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 4096, useAsync: true)显式控制行为 - 避免把
byte[]误传给Encoding.GetString()处理非文本数据(比如图片像素) - 调试时用
File.ReadAllBytes()快速看前几十字节十六进制,比盲目猜更可靠
二进制操作的核心不是“怎么写”,而是“谁定义了格式”。哪怕代码全对,只要和协议文档或 C 结构体对不上字段顺序、对齐、符号位,数据就不可用。建议先用十六进制编辑器对照验证几组手工构造的数据。









