file.openread 是获取只读 filestream 的最简方式,等价于 new filestream(path, filemode.open, fileaccess.read, fileshare.read),开销最小但需手动释放;若需写入、追加或随机访问,应改用 file.open 或显式构造 filestream 并配置缓冲区与异步选项。

用 File.OpenRead 最简方式获取只读流
直接打开文件为 FileStream,不缓存、不自动关闭,适合后续手动控制生命周期的场景。它等价于 new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read),底层开销最小。
- 路径不存在会抛
FileNotFoundException,权限不足抛UnauthorizedAccessException - 返回流不支持写入或 Seek(除非原文件可读写且用其他方式打开)
- 务必配合
using或显式调用Dispose(),否则句柄泄漏
using var stream = File.OpenRead(@"C:\data.bin"); // 后续读取操作
需要写入或随机访问?改用 File.Open
File.OpenRead 只读,若要写入、追加、重写或反复定位(如解析二进制协议),必须用 File.Open 并指定完整参数。
-
FileMode.Create:清空并重写;FileMode.Append:仅追加且自动定位到末尾 -
FileAccess.ReadWrite+FileShare.None保证独占访问,但会阻塞其他进程读写 - Windows 上对正在被记事本打开的文件调用
File.Open可能失败,因记事本默认以FileShare.Read打开,而你用了None
using var stream = File.Open(@"C:\config.json",
FileMode.OpenOrCreate,
FileAccess.ReadWrite,
FileShare.Read);
想自动管理生命周期?优先选 FileStream 构造函数 + using
File.Open* 系列是静态封装,实际仍走 FileStream 构造。显式构造更灵活,比如控制缓冲区大小或是否启用异步 I/O 标志。
- 第三个参数
bufferSize默认 4096,大文件顺序读建议设为 65536 减少系统调用次数 - 传
true给第四个参数isAsync,能让ReadAsync/WriteAsync真正基于 IOCP,否则只是线程池模拟 - 注意:.NET 6+ 中
isAsync: true在 Linux 上可能被忽略,仅 Windows 保证有效
using var stream = new FileStream(
@"D:\large.log",
FileMode.Open,
FileAccess.Read,
FileShare.Read,
bufferSize: 65536,
isAsync: true);
别把 File.ReadAllBytes 当流用
这个方法返回 byte[],不是流。有人误以为“读进内存就等于有了流”,但数组和流语义完全不同:数组不可变、无位置指针、无法复用缓冲区。
- 大文件(>100MB)调用它会触发 LOH 分配,GC 压力陡增
- 后续想“从中间开始解析”还得再包一层
new MemoryStream(bytes),多一次内存拷贝 - 如果只是校验哈希或转发 HTTP 响应体,直接用
FileStream管道传输更省内存
真正需要流语义时,绕过字节数组这层中间表示——磁盘文件到处理逻辑之间,保持流的连续性最省事也最可控。










