大文本文件笛卡尔乘积生成方案及C#代码性能优化咨询
性能问题根源
你现有代码的性能瓶颈非常明确,完全是不必要的重复IO操作导致的:
- 重复读取File1:每处理1条File2的记录就打开读取一次20MB的File1,6000次循环累计产生120GB的重复读磁盘开销,属于完全无意义的资源浪费
- 频繁控制台输出:循环内每次都调用
Console.WriteLine,大量IO等待会严重拖慢执行速度 - 字符串编解码冗余:用
StreamReader.ReadToEnd把字节流转成字符串再写入,多了两次编解码和内存拷贝开销 - 缓冲区未优化:默认的流缓冲区太小,写入150GB大文件会触发过多的系统级IO调用
- 若输入输出路径是网络共享路径,网络IO的延迟会进一步放大以上所有问题
优化方案
核心优化逻辑
- 预加载File1到内存:20MB体积极小,一次性读取为字节数组留存,全程只需要读1次File1
- 移除循环内高频控制台输出,仅保留必要的低频率进度提示即可
- 直接用字节流写入,跳过字符串编解码步骤
- 调大输出流的缓冲区到1MB以上,减少系统IO调用次数
- 条件允许的话,先把输入文件复制到本地磁盘处理,完成后再传到目标网络路径
优化后代码示例
using System; using System.IO; using System.Linq; using System.Text; class FileMergeTool { // 提前指定文件编码,根据你实际文件的编码调整,比如Encoding.GetEncoding("GBK")或者Encoding.UTF8 private static readonly Encoding FileEncoding = Encoding.UTF8; // 输出缓冲区大小设为2MB,大幅减少IO次数 private const int OutputBufferSize = 2 * 1024 * 1024; static void Main(string[] args) { DirectoryInfo di = new DirectoryInfo(@"\\InputPath"); var transmitFiles = di.GetFiles().Where(file => file.FullName.Contains("TRANSMIT_MASS")).ToArray(); string targetDate = DateTime.Now.AddDays(1).ToString("MMddyyyy"); foreach (FileInfo f in transmitFiles) { string[] tokens = f.Name.Split('_'); if (tokens[2] != targetDate) continue; string publishId = tokens[0]; string outputPath = Path.Combine(@"\\OutputPath", $"{publishId}.txt"); string file1Path = f.FullName; // 查找File2(SUBS门店文件) string storeFilePath = di.GetFiles() .Single(file => file.Name.StartsWith(publishId) && file.Name.Contains("SUBS")) .FullName; // 预加载File1全部内容到字节数组,全程仅读一次 byte[] file1Bytes = File.ReadAllBytes(file1Path); byte[] newLineBytes = FileEncoding.GetBytes(Environment.NewLine); int processedCount = 0; // 写入输出文件 using (var outputFs = new FileStream(outputPath, FileMode.Create, FileAccess.Write, FileShare.None, OutputBufferSize)) using (var storeReader = new StreamReader(storeFilePath, FileEncoding)) { string storeNumber; while ((storeNumber = storeReader.ReadLine()) != null) { if (storeNumber.Length <= 5) continue; // 写入当前门店编号行 byte[] storeBytes = FileEncoding.GetBytes(storeNumber); outputFs.Write(storeBytes, 0, storeBytes.Length); outputFs.Write(newLineBytes, 0, newLineBytes.Length); // 直接写入预加载的File1内容,不需要重复读磁盘 outputFs.Write(file1Bytes, 0, file1Bytes.Length); // 每处理1000条打一次进度,减少输出开销 if (++processedCount % 1000 == 0) { Console.WriteLine($"已处理{processedCount}条门店记录"); } } } Console.WriteLine($"文件{publishId}.txt处理完成,共写入{processedCount}条门店数据"); } } }
补充说明
- 不需要更换技术栈,C#完全可以满足需求,打包成Windows服务运行也没有任何问题
- 如果服务器磁盘是SSD,优化后写入150GB文件耗时应该在10分钟以内,就算是机械硬盘也不会超过半小时
- 如果必须用网络路径读写,可以在服务器上开启SMB3多通道优化,能显著提升网络文件读写速度
内容的提问来源于stack exchange,提问作者AK47
相关产品推荐
相关产品推荐

