且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何有效地写在C#中大文本文件?

更新时间:2023-02-15 16:32:31

文件I / O操作一般都是很好的现代操作系统进行了优化。您不该T试图组装在内存中的文件整个字符串......一块刚写出来一块。在的FileStream 会照顾缓冲和其他性能方面的考虑。



您可以通过移动使这个变化很容易。

 使用(StreamWriter的OUTFILE =新的StreamWriter(文件路径)){

该函数的顶部,并摆脱了的StringBuilder 直接写入,而不是文件。



有几个原因,你应该避免在内存中建立大量的字符串:




  1. 实际上,它可以表现较差,因为的StringBuilder 已为你写它来增加它的容量,从而重新分配和内存复制。

  2. ,可能需要更多的内存比你可以物理分配 - 这可能导致使用虚拟存储器(交换文件),其是比RAM慢得多的

  3. 对于真正的大文件(> 2GB),你会用完的地址空间(32位平台),将无法完整的。
  4. 要写入 StringBuilder的内容你必须使用一个文件的ToString()这有效地加倍进程的内存消耗,因为这两个副本必须在内存的一段的时间。如果你的地址空间是足够分散,使得存储器的单个连续块不能被分配​​该操作也可能失败。

  5. 醇>

    I am creating a method in C# which generates a text file for a Google Product Feed. The feed will contain upwards of 30,000 records and the text file currently weighs in at ~7Mb.

    Here's the code I am currently using (some lines removed for brevity's sake).

    public static void GenerateTextFile(string filePath) {
    
      var sb = new StringBuilder(1000);
      sb.Append("availability").Append("\t");
      sb.Append("condition").Append("\t");
      sb.Append("description").Append("\t");
      // repetitive code hidden for brevity ...
      sb.Append(Environment.NewLine);
    
      var items = inventoryRepo.GetItemsForSale();
    
      foreach (var p in items) {
        sb.Append("in stock").Append("\t");
        sb.Append("used").Append("\t");
        sb.Append(p.Description).Append("\t");
        // repetitive code hidden for brevity ...
        sb.AppendLine();
      }
    
      using (StreamWriter outfile = new StreamWriter(filePath)) {
          result.Append("Writing text file to disk.").AppendLine();
          outfile.Write(sb.ToString());
      }
    }
    

    I am wondering if StringBuilder is the right tool for the job. Would there be performance gains if I used a TextWriter instead?

    I don't know a ton about IO performance so any help or general improvements would be appreciated. Thanks.

    File I/O operations are generally well optimized in modern operating systems. You shouldn't try to assemble the entire string for the file in memory ... just write it out piece by piece. The FileStream will take care of buffering and other performance considerations.

    You can make this change easily by moving:

    using (StreamWriter outfile = new StreamWriter(filePath)) {
    

    to the top of the function, and getting rid of the StringBuilder writing directly to the file instead.

    There are several reasons why you should avoid building up large strings in memory:

    1. It can actually perform worse, because the StringBuilder has to increase its capacity as you write to it, resulting in reallocation and copying of memory.
    2. It may require more memory than you can physically allocate - which may result in the use of virtual memory (the swap file) which is much slower than RAM.
    3. For truly large files (> 2Gb) you will run out of address space (on 32-bit platforms) and will fail to ever complete.
    4. To write the StringBuilder contents to a file you have to use ToString() which effectively doubles the memory consumption of the process since both copies must be in memory for a period of time. This operation may also fail if your address space is sufficiently fragmented, such that a single contiguous block of memory cannot be allocated.