File.ReadAllText 读大文件会吃光内存
它把整个文件一次性加载进托管堆,哪怕只是想查某一行。100MB 的日志文件,
ReadAllText就会分配一块 100MB 的
string,GC 压力陡增,还可能触发
OutOfMemoryException。 替代方案:用
StreamReader.ReadLine()流式读取,边读边处理,内存占用基本恒定 注意
Encoding参数——默认 UTF-8 BOM 检测可能隐式多读几个字节,若确定无 BOM,显式传
new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)别在循环里反复调用
ReadAllText查多个小文件,合并为一次目录遍历 + 流读更高效
Directory.GetFiles 遍历深层嵌套目录极慢
它底层调用 Win32
FindFirstFile/FindNextFile,但每次匹配都做完整路径拼接和字符串操作,遇到几千个子目录时,CPU 时间大量耗在
Path.Combine和
string分配上。 改用
Directory.EnumerateFiles—— 返回
IEnumerable<string></string>,延迟执行,不预加载全量路径 加
SearchOption.TopDirectoryOnly显式限定范围,避免意外递归(尤其当符号链接存在时) 若只需文件名不含路径,用
new DirectoryInfo(path).EnumerateFiles().Select(f => f.Name),避开
GetFiles的路径拼接开销
File.Copy 不带 overwrite:true 覆盖时抛异常而非静默替换
很多人写
File.Copy(src, dst)后发现目标已存在就崩了,错误是
IOException: The file 'xxx' already exists.。这不是性能问题,但常导致重试逻辑失控、日志刷屏、甚至误删源文件。 必须显式传第三个参数:
File.Copy(src, dst, overwrite: true)注意权限:目标文件若被其他进程打开(如 Excel 正在编辑),即使
overwrite:true也会失败,得捕获
IOException并检查
HResult == -2147024864(即 ERROR_SHARING_VIOLATION) 跨卷复制(如 C: → D:)本质是“读+写+删”,比同卷复制慢一个数量级,且不可原子化;如需强一致性,先
Copy到临时位置,再
Move
FileStream 构造时不设 BufferSize 或 UseAsync 导致吞吐瓶颈
默认缓冲区大小是 4KB,对 SSD 或网络存储来说太小;而同步 I/O 在大文件复制时会让线程卡死,拖慢整个线程池。
读大文件:构造FileStream时传
bufferSize: 64 * 1024(64KB),减少系统调用次数 高并发写日志场景:用
FileOptions.Asynchronous+
WriteAsync,避免线程池饥饿;但注意 .NET 6+ 默认启用
ThreadPoolBoundHandle,旧版需手动配 别混用同步和异步方法——比如开了
Asynchronous却调
Write,会退化成同步阻塞,还多一层调度开销
最隐蔽的坑其实是路径解析:任何含
..或环境变量(如
%TEMP%)的路径,经
Path.GetFullPath后可能触发多次磁盘访问。生产环境里,少用
Environment.ExpandEnvironmentVariables+
Path.Combine拼接,优先走配置里的绝对路径或
AppContext.BaseDirectory这类已解析好的值。
