繁体   English   中英

C# 重用 StreamWriter 或 FileStream 但更改目标文件

[英]C# Reuse StreamWriter or FileStream but change destination file

一点背景...

我将要描述的直到实现 StreamWriter 的所有内容都是我无法更改的业务流程。

每个月我都会将大约 200 个不同的数据表提取到单独的文件中。 每个文件包含大约 400,000 行业务逻辑详细信息,用于超过 5,000-6,000 个不同的业务单元。

为了通过手头的工具有效地使用这些数据,我必须将这些文件分解为每个业务部门的单独文件......

每个文件 200 个文件 x 5000 个业务单位 = 100,000 个不同的文件。

我一直在做的方式是典型的 StreamWriter 循环......

          foreach(string SplitFile in List<BusinessFiles>)
          {  
            using (StreamWriter SW = new StreamWriter(SplitFile))
            {
                foreach(var BL in g)
                {
                    string[] Split1 = BL.Split(',');

                    SW.WriteLine("{0,-8}{1,-8}{2,-8}{3,-8}{4,-8}{5,-8}{6,-8}{7,-8}{8,-8}{9,-16}{10,-1}",
                     Split1[0], Split1[1], Split1[2], Split1[3], Split1[4], Split1[5], Split1[6], Split1[7], Split1[8], Convert.ToDateTime(Split1[9]).ToString("dd-MMM-yyyy"), Split1[10]);

                }
            }
          }

这样做的问题是,它需要过多的时间。 比如,有时处理所有文件可能需要 20 分钟。

分析我的代码显示,98% 的时间都花在了程序离开循环后系统处理 StreamWriter 上。

所以我的问题是......

有没有办法保持底层 Stream 打开并重用它来编写不同的文件?

我知道我可以 Flush() Stream 但我不知道如何让它开始完全写入另一个文件。 我似乎找不到无需调用另一个 StreamWriter 即可更改目标文件名的方法。

编辑:

当我分析代码时它显示的图片轮廓

这听起来很对。 20 分钟内 100,000 个文件超过每秒 83 个文件。 磁盘 I/O 几乎是您在单台计算机中可以做的最慢的事情。 Dispose()方法中的所有时间都是在关闭文件时等待缓冲区刷新到磁盘...这是将数据写入持久存储的实际时间,并且每个文件的单独using块是正确的方法以确保安全完成。

为了加快速度,很想看看异步处理(async/await),但我认为你不会在那里找到任何收获; 归根结底,这是一个 I/O 密集型任务,因此针对 CPU 调度进行优化甚至可能使事情变得更糟。 如果您可以将 output 更改为写入单个(索引)文件,则可以获得更好的收益,因此操作系统的磁盘缓冲机制可以更有效。

回答您的问题,您有一个选项(在构造函数上添加一个标志),但它与垃圾收集器密切相关,还要考虑多线程环境,它可能会一团糟。 也就是说这是重载的构造函数:

StreamWriter(流,编码,Int32,布尔值)

使用指定的编码和缓冲区大小为指定的 stream 初始化 StreamWriter class 的新实例,并可选择将 stream 保持打开状态。

public StreamWriter (System.IO.Stream stream, System.Text.Encoding? encoding = default, int bufferSize = -1, bool leaveOpen = true);

资源

我同意 Joel 的观点,时间主要是因为将数据写入磁盘。 但是,我对并行 IO 会更乐观一些,因为 SSD 比普通 HDD 能够更好地处理更高的负载。 所以我会尝试一些事情:

1.并行做事

将您的外循环更改为并行循环

Parallel.ForEach(
  myBusinessFiles, 
  new ParallelOptions(){MaxDegreeOfParallelism = 2}, 
   SplitFile  => {
      // Loop body
   });

尝试更改并行度以查看性能是否有所提高。 这假设数据是线程安全的。

2.尝试写入高速本地SSD

我假设您正在写入网络文件夹,这会增加一些额外的延迟,因此您可能会尝试写入本地磁盘。 如果您已经这样做了,请考虑获得更快的磁盘。 如果您之后需要将所有文件移动到网络驱动器,您可能不会获得任何东西,但它可以让您了解您从网络中获得的惩罚。

3. 尝试写入 Zip 存档

zip 档案可以在其中包含多个文件,同时仍然允许相当容易地访问单个文件。 这可以通过以下几种方式帮助提高性能:

  • 压缩。 我会假设你的数据很容易压缩,所以你会写更少的数据。
  • 更少的文件系统操作。 由于您只写入单个文件,因此可以避免文件系统的一些开销。
  • 由于集群大小减少了开销。 文件有一个最小大小,这可能会导致小文件的空间相当大的浪费。 使用存档可以避免这种情况。

您也可以尝试将每个文件保存在单独的 zip 存档中,但这样您将主要从压缩中受益。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM