Файлы Поиска Delphi и каталоги самый быстрый alghorithm

Я использую Delphi7, и мне нужно решение большой проблемы. Кто-то может предоставить мне более быстрый путь к поиску файлов и папок, чем использование findnext и findfirst? потому что я также обрабатываю данные для каждого файла/папки (дата создания/author/size/etc), и требуется много времени... Я искал много под WinApi, но вероятно я не имею, видят лучшую функцию для выполнения этого. Все примеры, которые я нашел сделанными в Delphi, используют findfirst и findnext...

Кроме того, я не хочу покупать компоненты или использовать некоторые свободные...

Заранее спасибо!

5
задан RBA 16 June 2010 в 15:02
поделиться

10 ответов

Я думаю, что любой компонент, который вы купите, также будет использовать findfirst / findnext. Конечно, рекурсивно. Я не думаю, что есть способ просматривать каждый каталог и файл, не просматривая каждый каталог и файл.

В качестве эталона, чтобы увидеть, достаточно ли быстр ваш код, сравните производительность с WinDirStat http://windirstat.info/ (до точки, где он собирает данные и готов построить свой график использования пространства.)
Исходный код доступен, если вы хотите увидеть, что они делают. Это C, но я ожидаю, что он использует те же вызовы API.

7
ответ дан 18 December 2019 в 07:28
поделиться

Если вы хотите получать действительно быстрые результаты поиска, подумайте об использовании Windows Search (API) или службы индексирования.

Другие улучшения могут заключаться в использовании потоков и разделении поиска файлов и сбора свойств файлов или просто выполнения потокового поиска.

2
ответ дан 18 December 2019 в 07:28
поделиться

Если вам нужно сканировать удаленный диск с таким количеством файлов, я бы настоятельно рекомендовал делать это по схеме "клиент-сервер", чтобы фактическое сканирование файлов всегда выполнялось локально, и только результаты получались удаленно. Это сэкономит вам много времени. Кроме того, все "сервера" могли бы сканировать параллельно.

1
ответ дан 18 December 2019 в 07:28
поделиться

Однажды я столкнулся с очень похожей проблемой, когда количество файлов в каталоге в сочетании с findfirst/findnext занимало больше времени, чем было разумно. С несколькими файлами это не проблема, но когда вы увеличиваете количество файлов до тысяч или десятков тысяч, производительность значительно падает.

Наше решение заключалось в использовании файла очереди в отдельном каталоге. По мере "добавления" файлов в систему они записывались в файл очереди (это был файл с фиксированной записью). Когда системе требовалось обработать данные, она проверяла, существует ли файл, и если да, то переименовывала его и открывала переименованную версию (таким образом, добавления могли происходить для следующего прохода процесса). Затем файл обрабатывался по порядку. Затем мы архивировали файл очереди и обработанные файлы в подкаталог, основанный на дате и времени (например: G:\PROCESSED\2010\06\25\1400 содержал файлы, запущенные в 14:00 6/25/2010).

Используя этот подход, мы не только достигли обработки файлов практически в режиме "реального времени" (с задержкой только на частоту обработки файла очереди), но и обеспечили обработку файлов в порядке их добавления.

1
ответ дан 18 December 2019 в 07:28
поделиться

С циклом findfirst / findnext не так много места для оптимизации, потому что он в основном связан с вводом-выводом: операционная система должна считывать эту информацию с вашего жесткого диска!

Доказательство: напишите небольшую программу, которая реализует простой цикл findfirst / findnext, который НИЧЕГО не делает с найденными файлами. Перезагрузите компьютер и запустите его в большом каталоге, отметив время, необходимое для завершения. Затем запустите его еще раз, не перезагружая компьютер. Вы заметите, что второй запуск выполняется значительно быстрее, потому что операционная система кэширует информацию!

Если вы точно знаете, что каталог, который вы пытаетесь просканировать, активно используется ОС из-за другого приложения, использующего данные (это поместит информацию о структуре каталогов в кэш ОС и сделает сканирование не привязанным к ввода-вывода) вы можете попробовать запустить несколько циклов findfirst / findnext параллельно, используя потоки. Обратной стороной этого является то, что если структура каталогов еще не находится в кеше ОС, ваш алгоритм снова привязан к жесткому диску, и это может быть хуже, чем оригинал, потому что теперь вы делаете несколько параллельных запросов ввода-вывода, которые требуют обрабатываться одним и тем же устройством.

Когда мне пришлось решать эту же проблему, я отказался от параллельных циклов, потому что ВТОРОЙ запуск приложения всегда намного быстрее, доказывая, что я привязан к вводу-выводу, и никакая оптимизация ЦП не исправит ввод-вывод. узкое место.

1
ответ дан 18 December 2019 в 07:28
поделиться

Я решил аналогичную проблему, используя два потока. Таким образом, я мог "обрабатывать" файл(ы) одновременно с их сканированием с диска. В моем случае обработка была значительно медленнее, чем сканирование, поэтому мне также пришлось ограничить количество файлов в памяти за один раз.

TMyScanThread

Сканируем файловую структуру, для каждого "попадания" добавляем путь+файл в TList/TStringList или аналогичный список, используя Syncronize(). Не забудьте Sleep() внутри цикла, чтобы у ОС тоже было немного времени.

Псевдокод для потока:

TMyScanThread=class(TThread)
private
  fCount : Cardinal;
  fLastFile : String;
  procedure GetListCount;
  procedure AddToList;  
public
  FileList : TStringList;
  procedure Execute; Override;
end;

procedure TMyScanThread.GetListCount;
begin
  fCount := FileList.Count;
end;

procedure TMyScanThread.AddToList;
begin
  FileList.Add(fLastFile);
end;

procedure TMyScanThread.Execute;
begin
     try
        { Get the list size }
        Syncronize( GetListCount );
        if fCount<500 then
        begin
          // FindFirst code goes here
          { Add a file to the list }
          fLastFile := SR.Name; // Store Filename in local var
          Syncronize( AddToList ); // Call method to add to list
          SleepEx(0,True);
        end else
          SleepEx(1000,True);
     finally
        Terminate;
     end;
end;

TMyProcessFilesThread

Получите самую старую запись в списке и обработайте ее. Затем выводим результаты в БД.

Этот класс реализован аналогично с Syncronized методами, которые обращаются к списку.

Одной из альтернатив вызовам Syncronize() является использование TCriticalSection. Реализация синхронизации между потоками часто является делом вкуса и поставленной задачи ...

1
ответ дан 18 December 2019 в 07:28
поделиться

Когда я начал сталкиваться с проблемами производительности при работе с большим количеством небольших файлов в файловой системе, я перешел к хранению файлов в виде больших двоичных объектов в базе данных. Нет причин, по которым связанная информация, такая как размер, создание и автор, также не могла быть сохранена в базе данных. Как только таблицы будут заполнены в базе данных, я подозреваю, что движок базы данных может выполнять гораздо более быструю работу по поиску записей (файлов), чем любое решение, которое мы собираемся предложить, поскольку код базы данных очень специализирован для эффективного поиска по большим данным. наборы. Это определенно будет более гибким, поскольку добавить новый поиск будет так же просто, как создать новый оператор Select. Пример: выберите * из файлов, где author = 'bob' и размер> 10000

Я не уверен, что этот подход вам поможет. Не могли бы вы рассказать нам подробнее о том, что вы делаете с этими файлами, и о критериях поиска.

0
ответ дан 18 December 2019 в 07:28
поделиться

Вы также можете попробовать BFS против DFS. Это может повлиять на производительность.

http://blogs.msdn.com/b/ericlippert/archive/2004/09/27/234826.aspx

http://en.wikipedia.org/wiki/Breadth-first_search

http://en.wikipedia.org/wiki/Depth-first_search

1
ответ дан 18 December 2019 в 07:28
поделиться

Единственное, что вы можете сделать для реального увеличения производительности - это разобрать MFT напрямую, если ваши тома NTFS. Это позволит вам перечислять файлы очень, очень быстро - мы говорим, по крайней мере, на порядок быстрее. Если все метаданные, которые вам нужны, являются частью записи MFT, ваш поиск будет завершен намного быстрее. Даже если вам придется выполнять дополнительные чтения для получения дополнительных метаданных, вы сможете очень быстро составить список файлов-кандидатов.

Недостатком является то, что вам придется разбирать MFT самостоятельно: В WinAPI нет функций для этого, о которых я знаю. Вы также будете беспокоиться о вещах, которые обычно делает за вас оболочка, беспокоясь о таких вещах, как жесткие ссылки, перекрестки, точки репарсинга, симлинки, ссылки оболочки и т.д.

Однако, если вам нужна скорость, увеличение сложности - единственный способ ее достичь.

Я не знаю ни одного доступного кода Delphi, который бы уже реализовал парсер MFT, так что вам, вероятно, придется либо использовать библиотеку стороннего производителя, либо реализовать его самостоятельно. Я собирался предложить NTFS Undelete с открытым исходным кодом (GPL), который был написан на Delphi, но он реализует разбор MFT через код Python и имеет встроенный мост Delphi-Python.

6
ответ дан 18 December 2019 в 07:28
поделиться

Если ваша программа работает в Windows 7 или Server 2008 R2, в функцию Windows FindFirstFileEx внесены некоторые усовершенствования, которые заставят ее работать немного быстрее. Вам придется скопировать и изменить функции VCL, чтобы включить новые параметры.

1
ответ дан 18 December 2019 в 07:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: