C# 文件系统API的性能陷阱 C#有哪些常见的文件操作写法会导致性能问题

来源:这里教程网 时间:2026-02-21 17:42:19 作者:

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

相关推荐