BinaryReader适合读已知格式的结构化二进制数据,如协议头、游戏存档;File.ReadAllBytes适用于小文件(几十KB内);FileStream.Read用于GB级大文件流式处理;需注意编码一致性、字节序及对齐问题。

BinaryReader 是最常用也最稳妥的二进制读取方式,但它不是唯一选择——关键看你要读什么、多大、是否需要精确控制字节布局。
用 BinaryReader 读结构化二进制数据
适合已知格式的文件,比如自定义协议头 + 字符串 + 整数序列(如配置块、游戏存档、序列化小对象)。BinaryReader 能按类型对齐读取:ReadInt32() 拿 4 字节当 int,ReadString() 自动识别前缀长度,ReadDouble() 拿 8 字节当 double。
注意点:
-
ReadString()依赖BinaryWriter.Write(string)写入时的编码和前缀规则;若文件是其他语言写的,很可能失败 - 构造
BinaryReader时传入的Encoding必须和写入时一致,否则中文乱码 - 不要在读完后调用
Close()同时关闭底层FileStream,除非你明确设置了leaveOpen = false(默认为false) - 示例:读一个版本号(
Int16)+ 四行诗(每行用WriteString()写入)
using (var fs = new FileStream("data.bin", FileMode.Open))
using (var br = new BinaryReader(fs, Encoding.UTF8))
{
var version = br.ReadInt16();
var line1 = br.ReadString();
var line2 = br.ReadString();
// ...
}
用 File.ReadAllBytes() 一次性加载小二进制文件
适合图标、小图片、加密密钥、证书等几十 KB 以内的文件。它返回 byte[],后续解析完全由你控制,不依赖任何编码或类型约定。
优点是简单直接,缺点是整块进内存——读一个 500MB 的视频文件会直接 OOM。
常见误用:
- 拿
Encoding.UTF8.GetString(bytes)强转任意二进制内容 → 出现 符号或崩溃 - 没做
File.Exists()检查就直接读 → 抛FileNotFoundException - 忽略文件权限,尤其在 Linux/macOS 上运行时路径有大小写或执行限制
正确姿势:
if (File.Exists(path))
{
byte[] data = File.ReadAllBytes(path);
// 接着用 BitConverter 或 Span<byte> 解析字段
}</byte>
用 FileStream.Read() 流式读取大二进制文件
当你处理 GB 级日志压缩包、传感器原始流、视频帧缓存时,必须避免全量加载。FileStream.Read() 配合循环缓冲区是最可控的方式。
核心要点:
- 永远检查返回值:
int bytesRead = fs.Read(buffer, 0, buffer.Length)—— 它可能小于请求长度,尤其在文件尾或网络流中 - 别用
ReadByte()单字节读,性能差一个数量级 - 如果要解析固定结构(如每 16 字节一个记录),用
Span+MemoryMarshal.Read比() BitConverter更快更安全 - 异步场景优先用
ReadAsync(),但注意FileStream默认不开启异步支持(需传FileOptions.Asynchronous)
byte[] buffer = new byte[8192];
using (var fs = new FileStream("huge.bin", FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.SequentialScan))
{
int bytesRead;
while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
{
ProcessChunk(buffer.AsSpan(0, bytesRead));
}
}
真正容易被忽略的是字节序(endianness)和对齐(padding)。C# 默认按本机序读写,但如果你读的是跨平台生成的二进制文件(比如嵌入式设备上传的数据),BinaryReader 不提供大端模式切换——这时必须手撸 BitConverter + Span 或引入 System.Buffers.Binary。










