C#读写二进制文件 C#如何操作二进制数据流

3次阅读

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

C#读写二进制文件 C#如何操作二进制数据流

BinaryReaderBinaryWriter 读写结构化二进制数据最稳妥

这两个类专为 .NET 的二进制序列化设计,自动处理字节序、类型长度和基础编码,比直接操作 Stream 更少出错。适用于保存/加载自定义结构体数值数组、字符串(需注意编码)等。

常见错误:用 BinaryWriter.Write(String) 写入后,用 BinaryReader.ReadString() 读取失败——因为后者依赖前缀长度(UTF-8 编码的 7 位变长整数),若文件非它所写,会抛 EndOfStreamException 或乱码。

  • 写字符串时,如需兼容性更强,改用 Write(byte[]) + Encoding.UTF8.GetBytes()
  • 读数值类型intdouble 等)完全安全,它们按小端序固定长度写入
  • 不要跨平台共享 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)dataSpan
  • 写入需手动复制: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 结构体对不上字段顺序、对齐、符号位,数据就不可用。建议先用十六进制编辑器对照验证几组手工构造的数据。

text=ZqhQzanResources