C# StreamWriter 与 File.AppendAllText 写入文本核心区别
一、底层本质
1. File.AppendAllText
File.AppendAllText("test.txt", "内容");
- 静态工具方法,一次性封装全套逻辑
- 内部流程:
- 判断文件是否存在
- 创建/打开文件流
FileStream - 实例化
StreamWriter - Write写入
- 立刻自动释放所有资源(using 内部封装)
- 关闭文件流
- 源码本质:单次临时创建并销毁 StreamWriter
2. StreamWriter
// 追加模式打开
using var sw = new StreamWriter("test.txt", append: true);
sw.WriteLine("内容");
// 多次写入...
sw.Flush();
- 流写入类,长生命周期、可复用
- 需要手动用
using释放资源,否则文件句柄占用 - 支持持续多次写入,文件只打开一次
二、核心差异对比表
| 对比维度 | File.AppendAllText | StreamWriter(append=true) |
|---|---|---|
| 文件打开次数 | 每次调用都重新打开+关闭文件 | 实例化一次,全程只打开一次 |
| 性能(少量写入) | 简单代码,差距不大 | 略优 |
| 性能(循环大量写入) | 极差,反复创建销毁流,频繁IO | 性能极高,一次打开循环写 |
| 资源释放 | 自动释放,无需using | 必须using/Dispose,否则锁文件 |
| 缓冲区控制 | 内部自动Flush,无法自定义缓冲 | 可手动Flush、自定义缓冲区大小 |
| 编码设置 | 重载可指定编码,默认UTF-8带BOM | 构造函数自由指定编码 |
| 支持逐行/分段 | 只能一次性传入完整字符串 | Write/WriteLine/WriteAsync 灵活分段写 |
| 异步版本 | File.AppendAllTextAsync |
WriteAsync、FlushAsync 细粒度异步 |
| 文件占用 | 每次调用瞬间占用后释放 | 对象存活期间持续持有文件句柄 |
| 适用场景 | 单次少量追加,一行/短句写入 | 循环批量、大文本、持续分段写入 |
三、关键细节差异
1. IO 开销(最重要)
场景:循环1万次追加文本
File.AppendAllText:
每次打开磁盘文件、创建流、写入、关闭句柄,磁盘频繁读写、系统调用开销巨大,速度慢几十上百倍。StreamWriter:
文件仅打开1次,全部写入完成后才关闭,内存缓冲区批量刷盘,IO次数极少。
2. 文件锁与占用
File.AppendAllText:方法执行完立刻释放文件,其他程序可随时读写。StreamWriter:只要对象没Dispose,文件会被进程独占,其他程序无法修改/删除该txt。
3. 缓冲区机制
StreamWriter 内置字符缓冲区,默认几千字符:
// 自定义4096字节缓冲区
using var sw = new StreamWriter("test.txt", true, Encoding.UTF8, 4096);
- 不调用
Flush()时,数据先存在内存,满了才自动写入磁盘; - File.AppendAllText 每次写完强制刷新缓冲区到磁盘。
4. 编码行为
两者都可自定义编码,默认规则一致:
- 无编码参数:UTF-8(带BOM)
File.AppendAllText("a.txt", "123", Encoding.UTF8);new StreamWriter("a.txt", true, Encoding.UTF8);
5. 异步写法区别
- File.AppendAllTextAsync:一次性异步写入整块文本
await File.AppendAllTextAsync("test.txt", "文本");
- StreamWriter 细粒度异步,适合流式输出:
using var sw = new StreamWriter("test.txt", true);
await sw.WriteLineAsync("第一行");
await sw.WriteLineAsync("第二行");
await sw.FlushAsync();
四、使用场景推荐
用 File.AppendAllText
- 仅单次、少量追加文本(日志单条记录、简单标记写入)
- 代码极简,不想手动管理流、using、释放资源
- 写完立刻释放文件,需要其他程序马上读取该文件
用 StreamWriter
- 循环批量写入(循环导出数据、持续写日志)
- 大文件、多行分段输出,需要多次Write
- 需要手动控制缓冲区、异步逐行写入
- 追求高性能,减少磁盘打开关闭次数
五、踩坑示例
坑1:循环调用AppendAllText性能灾难
// 不推荐!万次循环极慢
for(int i=0;i<10000;i++)
{File.AppendAllText("log.txt", $"日志{i}\r\n");
}
优化方案改用StreamWriter:
using var sw = new StreamWriter("log.txt", true);
for(int i=0;i<10000;i++)
{sw.WriteLine($"日志{i}");
}
sw.Flush();
坑2:忘记释放StreamWriter导致文件占用
// 错误:无using,文件一直被占用
StreamWriter sw = new StreamWriter("test.txt", true);
sw.WriteLine("xxx");
// 未Dispose,外部无法删除文件// 正确
using var sw = new StreamWriter("test.txt", true);
六、简单总结
- 单次少量写入:选
File.AppendAllText,代码简洁省心; - 多次循环/大批量写入:选
StreamWriter,性能碾压前者; - 底层关系:
File.AppendAllText是StreamWriter的一次性封装快捷方法。
