代码之家  ›  专栏  ›  技术社区  ›  jessegavin

如何有效地用C语言编写大型文本文件?

  •  34
  • jessegavin  · 技术社区  · 14 年前

    我正在用C创建一个方法,它为 Google Product Feed . 提要将包含30000条以上的记录,文本文件目前的重量在~7MB。

    这是我当前使用的代码(为了简洁起见,删除了一些行)。

    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());
      }
    }
    

    我想知道StringBuilder是否是适合这项工作的工具。如果我改为使用文本编写器,会有性能提升吗?

    我对IO性能知之甚少,因此任何帮助或一般改进都将不胜感激。谢谢。

    3 回复  |  直到 9 年前
        1
  •  65
  •   LBushkin    14 年前

    在现代操作系统中,文件I/O操作通常得到了很好的优化。 您不应该尝试在内存中组装文件的整个字符串…把它一块一块地写出来。这个 FileStream 将考虑缓冲和其他性能考虑。

    您可以通过移动:

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

    到函数的顶部,然后去掉 StringBuilder 而是直接写入文件。

    您应该避免在内存中构建大字符串有以下几个原因:

    1. 它实际上会表现得更差,因为 字符串拼接 必须在写入时增加其容量,从而导致内存重新分配和复制。
    2. 它可能需要比物理分配更多的内存,这可能导致使用比RAM慢得多的虚拟内存(交换文件)。
    3. 对于真正大的文件(>2GB),您将耗尽地址空间(在32位平台上),并且无法完成。
    4. 字符串拼接 必须使用的文件的内容 ToString() 这实际上使进程的内存消耗翻了一番,因为两个副本都必须在内存中保存一段时间。如果您的地址空间足够分散,以致无法分配单个连续内存块,则此操作也可能失败。
        2
  •  25
  •   Jon Skeet    14 年前

    只要移动 using 语句,使其包含整个代码,并直接写入文件。我觉得把这一切都记在记忆中没有意义。

        3
  •  10
  •   Alex Humphrey    14 年前

    使用streamwriter一次写入一个字符串。在StringBuilder中写入而不是缓存所有内容。