用 File.ReadLines
避免内存爆炸
直接读整个文件再按换行符切分(比如
File.ReadAllText+
Split('\n'))在大文件上会把全部内容加载进内存,几 GB 的日志一读就 OOM。而 File.ReadLines返回的是
IEnumerable<string></string>,按需逐行迭代,内存占用几乎恒定。
实操建议:
永远优先用File.ReadLines(path).Count(),不是
File.ReadAllLines如果文件编码非 UTF-8(比如 GB2312),必须显式传入
Encoding参数,否则可能乱码或抛
IOException注意:
Count()会遍历全部行,没有“跳过内容只数换行符”的捷径——行数本质就是行迭代器走完的次数
StreamReader
手动计数更可控
当需要跳过 BOM、处理不规范换行(
\r\n/
\n/
\r混用)、或中途提前退出时,
StreamReader更灵活。
示例关键逻辑:
int lineCount = 0;
using (var sr = new StreamReader(path, Encoding.UTF8))
{
while (sr.ReadLine() != null) lineCount++;
}
注意事项:
ReadLine()自动处理各种换行符,返回值为
null表示 EOF,比手动找
\n字节安全得多 若文件末尾缺换行符,最后一行仍会计入——这符合绝大多数场景下的“行数”语义 想跳过空行?加个
if (!string.IsNullOrWhiteSpace(line)) lineCount++
超大文件(>10GB)考虑用 Span<byte></byte>
扫描换行符
纯计数且文件极大时,
ReadLine()的字符串分配开销会累积成瓶颈。此时可绕过字符解码,直接扫描原始字节里的换行符(
0x0A或
0x0D 0x0A)。
但要注意:
必须确认文件编码是单字节(如 ASCII、UTF-8),多字节编码(UTF-16/32)不能这么干 Windows 换行符\r\n是两个字节,得避免把孤立的
\r或
\n误判为行尾 实际性能提升取决于文件大小和磁盘 I/O,SSD 上对几十 MB 文件没必要上这种方案
别踩这些坑
常见翻车点:
用File.ReadAllLines(path).Length—— 内存爆掉前你不会意识到它有多危险 忽略 BOM:UTF-8 带 BOM 的文件,
ReadLines默认能处理,但自己用
StreamReader时没传
Encoding.UTF8可能吞掉首行 把
Environment.NewLine当文件换行符用——它只是当前系统的默认换行,和文件实际使用的无关 在非托管环境(如某些嵌入式 .NET 运行时)中,
File.ReadLines可能不可用,得回退到
StreamReader
行数统计看着简单,但文件编码、换行约定、内存约束三者一叠加,最容易在“以为没问题”的地方卡住。尤其线上日志分析脚本,务必用真实大文件压测一遍。
