Каталог C#, перечисляющий массивный каталог

Вот сценарий:

У меня есть каталог с 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 минут создают файл.

5 ответов

Решение

Это может помочь, если вы не создадите экземпляр 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 миллионов файловых дескрипторов в память. В зависимости от того, сколько у вас памяти, вы можете поменяться местами. Попробуйте разбить его на более мелкие куски, отфильтровывая по имени файла.

Первое, что мне нужно знать, это где замедление? для выполнения Directory.GetFiles() требуется 89 минут или задержка распределяется по вызовам FileInfo file_info = new FileInfo(file);?

Если задержка связана с последним, вы, вероятно, можете ускорить процесс, получив имя файла по пути, вместо создания экземпляра FileInfo для получения имени файла.

System.IO.Path.GetFileName(file);

По моему опыту, это Directory.GetFiles это замедляет вас (кроме вывода на консоль). Чтобы преодолеть это, P/Invoke в FindFirstFile/ FindNextFile, чтобы избежать всего потребления памяти и общего отставания.

При использовании Directory.EnumerateFiles не нужно сначала загружать все имена файлов в память. Проверьте это: C# directory.getfiles справка памяти

В вашем случае код может быть:

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

Из этого документа сказано, что:

Методы EnumerateFiles и GetFiles отличаются следующим образом: когда вы используете EnumerateFiles, вы можете начать перечисление коллекции имен до того, как будет возвращена вся коллекция; когда вы используете GetFiles, вы должны подождать, пока весь массив имен будет возвращен, прежде чем вы сможете получить доступ к массиву. Поэтому, когда вы работаете со многими файлами и каталогами, EnumerateFiles может быть более эффективным.

Так что, если у вас достаточно памяти, Directory.GetFiles в порядке. Но Directory.EnumerateFiles намного лучше, когда папка содержит миллионы файлов.

Другие вопросы по тегам