file.readalltext读大文件会吃光内存,应改用streamreader.readline流式读取;directory.getfiles遍历深层目录极慢,推荐directory.enumeratefiles;file.copy需显式设overwrite:true;filestream应设合适buffersize并避免混用同步异步方法。

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 这类已解析好的值。











