【问题标题】:C# Directory listing massive directoryC# Directory 列出海量目录
【发布时间】:2009-12-21 16:45:40
【问题描述】:

这是场景:

我有一个包含 2+ 百万个文件的目录。我下面的代码在大约 90 分钟内写出所有文件。有没有人有办法加快速度或使这段代码更有效?我也想只写出列表中的文件名。

string lines = (listBox1.Items.ToString());
string sourcefolder1 = textBox1.Text;  
string destinationfolder = (@"C:\anfiles");  
using (StreamWriter output = new StreamWriter(destinationfolder + "\\" + "MasterANN.txt"))  
{  
    string[] files = Directory.GetFiles(textBox1.Text, "*.txt");  
    foreach (string file in files)  
    {  
        FileInfo file_info = new FileInfo(file);
        output.WriteLine(file_info.Name);  
    }  
 }  

速度慢的是它一次写出 1 行。

大约需要 13-15 分钟才能得到它需要写出的所有文件。

接下来的 75 分钟正在创建文件。

【问题讨论】:

  • 它与您的问题无关,但不要这样做:destinationfolder + "\\" + "MasterANN.txt 改为使用 Path.Combine(destinationFolder, "MasterANN.txt")
  • 如果使用 dir 从命令行执行此操作会更快吗?例如,“dir /b *.txt > c:\anfiles\MasterANN.txt”。如果是这样,您可以使用 dir(使用 Process 类)。

标签: c# file-io


【解决方案1】:

如果您不为每个文件创建一个 FileInfo 实例,这可能会有所帮助,请改用 Path.GetFileName:

string lines = (listBox1.Items.ToString());  
        string sourcefolder1 = textBox1.Text;  
        string destinationfolder = (@"C:\anfiles");  
        using (StreamWriter output = new StreamWriter(Path.Combine(destinationfolder, "MasterANN.txt"))  
        {  
            string[] files = Directory.GetFiles(textBox1.Text, "*.txt");  
            foreach (string file in files)  
            {  
                output.WriteLine(Path.GetFileName(file));
            }  
        }

【讨论】:

  • 太棒了!谢谢,这确实做到了。
【解决方案2】:

您正在将 2+ 百万个文件描述符读入内存。根据你有多少内存,你很可能正在交换。尝试通过过滤文件名将其分成更小的块。

【讨论】:

    【解决方案3】:

    我需要知道的第一件事是,减速在哪里? Directory.GetFiles() 执行需要 89 分钟还是延迟分散在对 FileInfo file_info = new FileInfo(file); 的调用上?

    如果延迟来自后者,您可以通过从路径获取文件名而不是创建 FileInfo 实例来获取文件名来加快速度。

    System.IO.Path.GetFileName(file);
    

    【讨论】:

    • 没关系 FileInfo file_info = new FileInfo(File; output.WriteLine(file_info.Name);
    【解决方案4】:

    根据我的经验,是Directory.GetFiles 让您放慢了速度(除了控制台输出)。为了克服这个问题,P/Invoke 到 FindFirstFile/FindNextFile 以避免所有的内存消耗和一般的延迟。

    【讨论】:

      【解决方案5】:

      使用Directory.EnumerateFiles 不需要先将所有文件名加载到内存中。看看这个:C# directory.getfiles memory help

      在您的情况下,代码可能是:

      using (StreamWriter output = new StreamWriter(destinationfolder + "\\" + "MasterANN.txt"))
      {
          foreach (var file in Directory.EnumerateFiles(sourcefolder, "*.txt"))
          {
              output.WriteLine(Path.GetFileName(file));
          }
      }
      

      来自this doc,它说:

      EnumerateFiles 和 GetFiles 方法的区别如下: 使用 EnumerateFiles 时,可以在返回整个集合之前开始枚举名称集合;当您使用 GetFiles 时,您必须等待返回整个名称数组,然后才能访问该数组。因此,当您处理许多文件和目录时,EnumerateFiles 会更高效。

      所以如果你有足够的内存,Directory.GetFiles 就可以了。但是当文件夹包含数百万个文件时,Directory.EnumerateFiles 会更好。

      【讨论】:

      • 不仅比 Directory.GetFiles 更好而且更快。实际上,这是众所周知的“技巧”,也就是最佳答案(考虑到您不希望 p/Invoke 和第三方库混淆)。
      猜你喜欢
      • 2018-03-20
      • 1970-01-01
      • 2012-01-31
      • 1970-01-01
      • 2017-02-06
      • 1970-01-01
      • 1970-01-01
      • 2015-08-15
      • 2013-08-17
      相关资源
      最近更新 更多