file.readalllines + array.reverse适合中小文件,自动处理换行符和bom;大文件须用stack逐行读压栈再弹出写入,避免内存溢出;file.readlines不可直接反转,预扫描+filestream仅适用于特定超大文件场景。

用 File.ReadAllLines + Array.Reverse 最快也最安全
直接读全部行再反转,适合中小文件(几百MB以内)。它不搞花哨流式操作,避免手动管理缓冲、编码、换行符差异带来的坑。
常见错误是误用 StreamReader 从末尾往前读——Windows 换行符 \r\n 跨字节,纯字节倒着扫会切裂行;UTF-8 多字节字符更没法靠后往前跳。
-
File.ReadAllLines自动处理 BOM 和换行符(\n、\r\n、\r),返回干净的字符串数组 - 反转后用
File.WriteAllLines写出,编码默认 UTF-8(无 BOM),如需带 BOM 或 ANSI,显式传Encoding.UTF8或Encoding.Default - 内存占用 = 文件文本大小 × 2 左右(读一份、存一份反转后),别硬套在几个 GB 的日志上
string[] lines = File.ReadAllLines("input.txt");
Array.Reverse(lines);
File.WriteAllLines("output.txt", lines);
大文件必须用 Stack<string></string> 缓存行,不能全读进内存
超过 500MB 就该警惕。File.ReadAllLines 会触发 GC 压力甚至 OutOfMemoryException,尤其在 32 位进程或内存受限环境。
核心思路:正向逐行读,压入 Stack<string></string>,再逐个弹出写入目标文件。栈天然满足 LIFO,比 List.Reverse() 少一次遍历。
- 用
StreamReader配合ReadLine(),它正确识别各种换行,且按行缓冲,内存友好 - 别用
File.ReadLines+ToList—— 看似延迟执行,但ToList仍会全加载到内存 - 注意:
Stack不是线程安全的,单线程场景没问题;并发写入要加锁或换ConcurrentStack(但通常没必要)
var stack = new Stack<string>();
using (var reader = new StreamReader("input.txt"))
{
string line;
while ((line = reader.ReadLine()) != null)
stack.Push(line);
}
using (var writer = new StreamWriter("output.txt"))
{
while (stack.Count > 0)
writer.WriteLine(stack.Pop());
}
File.ReadLines 不能直接反转,别被名字误导
File.ReadLines 返回 IEnumerable<string></string>,是延迟执行的“管道”,不是可索引集合。你不能对它调 Reverse() 后直接写——那会触发两次完整遍历:第一次算长度(为反转准备),第二次才真正读取,等于白读两遍,还可能因文件被修改导致行为不一致。
更糟的是,如果后续接 ToArray() 或 ToList(),就又回到内存爆炸的老路。
- 想“边读边反”?不存在。磁盘文件不支持随机按行寻址,除非你预先扫描一遍记录每行起始偏移(见下一条)
-
File.ReadLines的唯一优势是流式消费,比如只取前100行反向输出——那就先Take(100)再Reverse(),但这是子集场景,不是全文逆序 - 若坚持用 LINQ,至少写成
File.ReadLines(...).ToArray().AsSpan().Reverse(),避免Reverse()LINQ 扩展方法的额外开销
真要极致性能?预扫描 + 随机访问 + FileStream 定位
仅适用于超大文件(数 GB)、重复处理、且行长度相对均匀的场景,比如固定格式日志。它绕过 .NET 行读取层,自己解析换行符并记录每行起始位置,之后从后往前用 FileStream.Seek 直接跳转读取。
代价很高:代码量翻倍、编码需手动处理(如 UTF-8 字节边界)、BOM 判断、空行/超长行容错都要自己写。99% 的情况没必要。
- 扫描阶段必须用
FileStream+Span<byte></byte>批量读,避免单字节Read()性能灾难 - 换行符检测不能简单找
\n:Windows 是\r\n,老 Mac 是\r,得兼容;多字节 UTF-8 中\n不会出现在中间字节,可安全扫描 - 记录的是字节偏移,不是字符索引,
StreamReader无法直接 Seek,必须用FileStream+Encoding.GetString解码片段
这事做一次可以,写成通用工具类就得反复验证边界——比如最后一行没换行符、文件结尾是 \r 但缺 \n、BOM 后紧跟换行…… 实际项目里,多数人选 Stack 方案,稳。










