Самый быстрый способ найти самый старый файл в каталоге, используя Delphi - PullRequest
2 голосов
/ 23 марта 2010

HI

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

Я пытаюсь найти самый старый видеофайл на диске, но с помощью FindFirst/FindNext сравнение времени создания файла занимает бесконечно долго.

Кто-нибудь знает более эффективный способ поиска самого старого файла в каталоге?Мы удаленно подключаемся к компьютерам из центрального офиса.

С уважением, Питер

- Обновление

Спасибо всем за ответыВ конце я использовал следующее:

  1. Подключите диск ('w:') к удаленному компьютеру с помощью windows.WNetAddConnection2
    // Выполните команду dir на удаленном компьютере с помощью cmd.exe /c dir
    // ПРИМЕЧАНИЕ. Буквы дисков относятся к удаленному компьютеру.(параметр psexec -w)
  2. psexec \\<IPAddress> -i /accepteula -w "c:\windows\system32" cmd.exe "/c dir q:\video /OD /TC /B > q:\dir.txt"
  3. // Прочитать первую строку «w: \ dir.txt», чтобы получить самый старый файл в этом каталоге.
  4. // Отключение от удаленного компьютера с помощью windows.WNetCancelConnection2

Ответы [ 4 ]

1 голос
/ 23 марта 2010

Вы также можете попробовать FindFirstFileEx с параметром FindExInfoBasic, а в Windows 7 или Server 2008 R2 или более поздней версии FIND_FIRST_EX_LARGE_FETCH, что должно улучшить производительность .

0 голосов
/ 23 марта 2010

У меня была почти та же проблема с программным обеспечением факс-сервера, которое я разработал. Мне пришлось отправлять факсы в порядке их получения от тысяч (все они хранятся в каталоге). Решение, которое я принял (которое медленно запускается, но быстро запускается), состоит в том, чтобы создать отсортированный список всех файлов, используя

SearchRec.Time 

в качестве ключа. После того, как файл находится в списке, я устанавливаю атрибуты файла как faSysFile:

NewAttributes := Attributes or faSysFile;

Теперь, когда я делаю новый поиск с

FileAttrs := (faAnyFile and not faDirectory);

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

procedure FileSetSysAttr(AFileName: string);
var
  Attributes, NewAttributes: Word;
begin
  Attributes := FileGetAttr(AFileName);
  NewAttributes := Attributes or faSysFile;
  FileSetAttr(AFileName, NewAttributes);
end;

procedure FileUnSetSysAttr(AFileName: string);
var
  Attributes, NewAttributes: Word;
begin
  Attributes := FileGetAttr(AFileName);
  NewAttributes := Attributes and not faSysFile;
  FileSetAttr(AFileName, NewAttributes);
end;

procedure PathUnSetSysAttr(APathName: string);
var
  sr: TSearchRec;
  FileAttrs: Integer;
begin
  FileAttrs := (faAnyFile and not faDirectory) and (faAnyFile or faSysFile);
  APathName := IncludeTrailingBackslash(APathName);
  if SysUtils.FindFirst(APathName + '*.*', FileAttrs, sr) = 0 then
  try
    repeat
      if (sr.Attr and faDirectory) = 0 then
        FileUnSetSysAttr(APathName + sr.Name);
    until SysUtils.FindNext(sr) <> 0;
  finally
    SysUtils.FindClose(sr);
  end;
end;

Я знаю, что это не лучшее решение, но оно работает для меня.

0 голосов
/ 23 марта 2010

Если вы можете запустить на удаленном компьютере что-то, что может перебирать каталоги, это будет самый быстрый подход.Если вы хотите использовать пример Мейсона, попробуйте запустить его с PsExec от SysInternals.

Если вы можете запускать приложение только локально, то нет, более быстрого способа, чем FindFirst / FindNext, и ничегоиначе вы будете в конечном итоге сводиться к этому.Если ваш локальный компьютер работает под управлением Windows 7, вы можете использовать вместо него FindFirstFileEx, у которого есть флаги, указывающие, что он должен использовать большие буферы для передач, и что он не должен читать псевдоним 8.3, что может немного помочь скорости.

0 голосов
/ 23 марта 2010

Сначала возьмите с этой страницы процедуру RunDosAppPipedToTStrings на , как запустить программу DOS и направить ее вывод в TStrings .В этом примере используется свойство Lines TMemo, но вы можете передавать любые строки TString, например TStringList.Обратите внимание, что это произойдет автоматически, если CreateProcess вернет false.Возможно, вы захотите добавить случай else в блок if ifProcess, который вызывает исключение.

Затем создайте простой пакетный файл в той же папке, что и ваш EXE-файл.Назовите это getdir.bat.Все, что он должен сказать, это:

dir %1

Это создает список каталогов любой папки, которую вы передаете ему.К сожалению, «dir» - это команда ключевого слова DOS, а не программа, поэтому вы не можете вызвать ее напрямую.Упаковка в пакетный файл обходит это.Это немного взломать, но это работает.Если вы сможете найти лучший способ запуска DIR, тем лучше.

Вы захотите вызвать RunDosAppPipedToTStrings с кодом, который выглядит примерно так:

procedure GetDirListing(dirname: string; list: TStringList);
const
   CMDNAME = '%s\getdir.bat "%s"';
var
   path: string;
begin
  list.Clear;
  path := ExcludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0)));
  RunDosAppPipedToTStrings(format(CMDNAME, [path, dirname]), list, false);
end;

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...