WriteAllText与AppendAllLines性能对比及差异原因咨询
两种文件写入方式的区别与性能差异解析
核心区别
两种实现的差异主要体现在内存数据构建逻辑和文件写入的前置操作上:
1. 内存中数据拼接的方式不同
- WriteAllText 版本:使用
string类型变量循环拼接内容。由于C#的string是不可变类型,每次执行+=操作都会创建一个全新的字符串对象,旧对象会被标记为垃圾回收。当处理数千条记录时,会产生大量临时字符串,既占用额外内存,还会触发频繁的垃圾回收(GC),这是性能瓶颈的核心。 - AppendAllLines 版本:使用
List<string>存储每一行的完整内容。List基于数组实现,添加元素的开销极低(仅在扩容时产生少量额外成本),且每一行的字符串是一次性拼接完成,不会生成大量临时对象。
2. 文件写入的前置准备不同
- WriteAllText:需要先在内存中构建出包含所有内容的巨型字符串,再一次性写入文件。但构建这个巨型字符串的过程已经消耗了绝大多数时间,文件写入本身的开销反而不是重点。
- AppendAllLines:先将所有行存入
List<string>,再通过方法一次性写入所有行。写入阶段的效率和WriteAllText的写入步骤相差不大,但因为内存数据构建过程高效,所以整体耗时极低。
性能差异的关键原因
性能差距的核心不在于File.WriteAllText和File.AppendAllLines方法本身,而在于内存中构建数据的时间复杂度:
- 普通
string循环拼接的时间复杂度是O(n²):每次拼接都要复制现有字符串的全部内容到新对象,记录数越多,复制的内容量呈指数级增长,耗时急剧上升。 List<string>的方式是O(n):每一行仅做一次拼接,添加到List的操作平均为O(1),整体数据构建的开销随记录数线性增长,效率远高于前者。
优化建议
如果要保留File.WriteAllText的写法,可以用StringBuilder替代普通string拼接,避免大量临时对象的创建,性能会接近AppendAllLines版本:
StringBuilder sb = new StringBuilder(); foreach (Demands myDemands in demandList) { sb.Append($"{myDemands.DEVICETYPE},"); sb.Append($"{myDemands.DEVICENUMBER},"); sb.Append($"{myDemands.LOCATION},"); sb.Append($"{myDemands.METERINDEX},"); sb.Append($"{myDemands.LOSSESPERPHASE},"); sb.Append($"{myDemands.LoadModelName},"); sb.Append($"{myDemands.DEMANDTYPE},"); sb.AppendLine($"{myDemands.AAmp}"); } File.WriteAllText(targetFileName, sb.ToString());
内容的提问来源于stack exchange,提问作者JerryW
相关产品推荐
相关产品推荐

