Справка C# directory.getfiles памяти
Вот код, который я использую:
using (StreamWriter output = new StreamWriter(Path.Combine(masterdestination, "Master.txt")))
{
string masterfolders = sourcefolder1;
string[] filess = Directory.GetFiles(masterfolders, "*.txt");
foreach (string file in filess)
{
output.WriteLine(Path.GetFileName(file));
}
}
Этот код будет искать все файлы в указанной пользователем директории для любого текстового файла. Эти каталоги иногда содержат 2 миллиона файлов.
отслеживая этот процесс во время его работы, я видел, как он поднялся до 800 МБ памяти. Есть ли способ, которым я могу сохранить скорость этого процесса и ограничить память, которую он использует? Или это читать и сбрасывать и продолжать? Хеш-таблица? Любая идея была бы потрясающей.
5 ответов
Directory.GetFiles действительно отстой. Если вы можете использовать.NET 4.0, вы должны изучить использование Directory.EnumerateFiles. Из документов:
Методы EnumerateFiles и GetFiles отличаются следующим образом: когда вы используете EnumerateFiles, вы можете начать перечисление коллекции имен до того, как будет возвращена вся коллекция; когда вы используете GetFiles, вы должны подождать, пока весь массив имен будет возвращен, прежде чем вы сможете получить доступ к массиву. Поэтому, когда вы работаете со многими файлами и каталогами, EnumerateFiles может быть более эффективным.
Если вы не можете использовать Fx4, лучше всего написать свой собственный FileEnumerator. Вот один пример.
Directory.GetFiles
должен создать список всех подходящих файлов, прежде чем он сможет вернуться. Только тогда вы можете перечислить их. Поэтому, конечно, это дорого, когда есть много подходящих файлов. Он может даже создать список всех файлов внутри.
Если вы можете использовать.NET 4.0, то вы можете использовать Directory.EnumerateFiles
что позволяет избежать этой проблемы, возвращая один файл за раз. Если вы не можете, то я бы посоветовал вам написать это на C++, а не на C#.
В C++ вы можете использовать FindFirstFile
который также возвращает файлы по одному за раз.
// iterate though the files in this directory
//
TCHAR szWild[MAX_PATH];
PathCombine(szWild, masterfolders, _T("*.txt"));
WIN32_FIND_DATA fd;
HANDLE hFind = FindFirstFile(szWild, &fd);
if (INVALID_HANDLE_VALUE != hFind)
{
do {
TCHAR szFileName[MAX_PATH];
PathCombine(szFileName, masterfolders, fd.cFileName);
// write szFilename to output stream..
} while (FindNextFile(hFind, &fd));
FindClose (hFind);
}
Если вы осуществляете поиск, то я предлагаю вам использовать Windows Search 4.0
Как уже упоминалось в ответе здесь, если вы используете.NET 4.0, вы можете использовать статический метод EnumerateFiles в классе Directory, чтобы получить IEnumerable<string>
вместо строки [], которая приводит ко всему потреблению памяти.
Если вы работаете с версией.NET до.NET 4.0, вы можете легко имитировать эту функциональность, вызывая методы FindFirstFileEx, FindNextFile и т. Д. И т. Д. Через слой P/Invoke.
Затем для каждого файла, возвращаемого при вызове FindFirstFile/FindNextFile, вы должны вернуть элемент.
Это сократит потребление памяти, как это делает EnumerateFiles для каталогов с большим количеством файлов, потому что вы не загружаете их все в массив заранее, а отдаете их для обработки по мере их нахождения.