Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 30.10.2013, 14:15   #1
Winexcel
Форумчанин
 
Регистрация: 26.08.2013
Сообщений: 187
По умолчанию Delphi FindFirst, не находит половину файлов.

Собственно такая картина:
Использую функцию FindFirst для поиска всех файлов в каталоге, функция не все файлы выводит, использую рекурсию для найденного каталога в директории. Если же не искать в каталогах а искать на корневом диске то функция находит все файлы, собственно код:

Код:
function SlashSep(Path, FName: string): string;
begin
 if Path[Length(Path)] <> '\' then
  Result := Path + '\' + FName
 else Result := Path + FName;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 Memo1.Lines.Clear;
 ScanFolder(edLookIn.Text);
end;

procedure TForm1.ScanFolder(Folder: String);
var
 sr: TSearchRec;
 FileName:String;
begin
 if FindFirst(Folder+'\*.*', faAnyFile, sr) = 0 then
  begin
   repeat
    if (sr.Name='.') or (sr.Name='..') then
     continue;

    FileName := SlashSep(Folder, sr.Name);

    // Ýòî äèðåêòîðèÿ?
    if (sr.Attr and faDirectory) = faDirectory then
     begin
      ScanFolder(FileName);
      Continue;
     end;

    // Íàéäåí ôàéë
      Memo1.Lines.Add(FileName);
   until FindNext(sr) <> 0;
   FindClose(sr);
  end;
  memo1.Lines.SaveToFile(extractfilepath(paramstr(0))+'log.txt');
end;
Если мы будем пропускать рекурсию:

Код:
    if (sr.Attr and faDirectory) = faDirectory then
     begin
      ScanFolder(FileName);
      Continue;
     end;
Изменив код на следующий
Код:
    if (sr.Attr and faDirectory) = faDirectory then
Continue;
То функция находит все файлы, вот пример действия с рекурсией:
Код:
C:\1.dat
C:\1.txt
C:\AUTOEXEC.BAT
C:\boot.ini
C:\Bootfont.bin
C:\CONFIG.SYS
C:\Cookies
C:\csb.log
C:\Deliker.exe
//ПЕРЕШЛИ НА ДРУГОЙ КАТАЛОГ 
C:\Documents and Settings\All Users\Application Data\Adobe\Acrobat\11.0\Replicate\Security\directories.acrodata
C:\Documents and Settings\All Users\Application Data\Adobe\Adobe PDF\Extras\MAGAZINE Ad 2006 JPN.joboptions
C:\Documents and Settings\All Users\Application Data\Adobe\Adobe PDF\Extras\PDFX1a 2001 JPN.joboptions
C:\Documents and Settings\All Users\Application Data\Adobe\Adobe PDF\Extras\PDFX1a 2003 JPN.joboptions
C:\Documents and Settings\All Users\Application Data\Adobe\Adobe PDF\Extras\PDFX1a 2003.joboptions
C:\Documents and Settings\All Users\Application Data\Adobe\Adobe PDF\Extras\PDFX3 2002 JPN.joboptions
C:\Documents and Settings\All Users\Application Data\Adobe\Adobe PDF\Extras\PDFX3 2003 JPN.joboptions
C:\Documents and Settings\All Users\Application Data\Adobe\Adobe PDF\Extras\PDFX3 2003.joboptions
C:\Documents and Settings\All Users\Application Data\Adobe\Adobe PDF\Extras\PDFX4 2008 JPN.joboptions
Прокомментировал где баг://ПЕРЕШЛИ НА ДРУГОЙ КАТАЛОГ

И собственно код без рекурсии пропуская директории:

Код:
C:\1.dat
C:\1.txt
C:\AUTOEXEC.BAT
C:\boot.ini
C:\Bootfont.bin
C:\CONFIG.SYS
C:\Cookies
C:\csb.log
C:\Deliker.exe
C:\Export.txt
C:\hiberfil.sys
C:\interbase.log
C:\IO.SYS
C:\MSDOS.SYS
C:\NTDETECT.COM
C:\ntldr
C:\Olike Bot Crack.exe
C:\oLikeBot.Deobf.exe
C:\oLikeBot.exe
C:\outfile.txt
C:\pagefile.sys
C:\PiarBot 1.7 by VANS.exe
C:\Project1.exe
C:\shopping.log
C:\TEMPtest.vbs
C:\WPI_Log.txt
C:\Òåêñòîâêà ïîä äîð.txt
Сразу видно что файлов в корневом каталоге гораздо больше чем выдаёт программа с рекурсией, код приведенный выше из библии делфи от Фленов. Скажите в чём ошибся автор такой книги.
Winexcel вне форума Ответить с цитированием
Старый 30.10.2013, 14:27   #2
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

У меня отработала норм.
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 30.10.2013, 15:06   #3
Arigato
Высокая репутация
СуперМодератор
 
Аватар для Arigato
 
Регистрация: 27.07.2008
Сообщений: 15,551
По умолчанию

А почему вы решили, что сначала будут найдены все файлы, а только потом каталоги? Ведь может быть и вперемешку.
Arigato вне форума Ответить с цитированием
Старый 30.10.2013, 15:18   #4
Winexcel
Форумчанин
 
Регистрация: 26.08.2013
Сообщений: 187
По умолчанию

Цитата:
Сообщение от Arigato Посмотреть сообщение
А почему вы решили, что сначала будут найдены все файлы, а только потом каталоги? Ведь может быть и вперемешку.
Логика у вас тоже есть. Но, в конец процедуры я поставил вывод сообшения. showmessage. Дак вот, когда процедера габотает с рекурсией и вызывает себя с найденным каталогом, то после вызова себя завершается...собственно это и проблема. Да и не логично было бы писать все в перемешку. Нужно чтобы все файлы выводило по каталогам. В чем проблема н могу понять. Не мог же сам Фленов тут допустить ошибку..
ПЫСЫ сначала написал свой исходник с нуля(стараюсь все писать сам), думал я ошибку допустил, потом взял исходник из примеров, работает также.

Последний раз редактировалось Winexcel; 30.10.2013 в 15:22.
Winexcel вне форума Ответить с цитированием
Старый 30.10.2013, 15:33   #5
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Цитата:
Не мог же сам Фленов тут допустить ошибку..
Не обожествляй его )
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 30.10.2013, 16:20   #6
Winexcel
Форумчанин
 
Регистрация: 26.08.2013
Сообщений: 187
По умолчанию

Ладно, хорошо, допустим что процедуры запускаются и раскидывают файлы в беспорядочно, создал критическую секцию:

Код:
procedure TForm1.ScanFolder(Folder: String);
var
 sr: TSearchRec;
 FileName:String;
begin
 if FindFirst(Folder+'\*.*', faAnyFile, sr) = 0 then
  begin
  cs.Enter;

   repeat
    if (sr.Name='.') or (sr.Name='..') then
     continue;

    FileName := SlashSep(Folder, sr.Name);

    // Ýòî äèðåêòîðèÿ?
    if (sr.Attr and faDirectory) = faDirectory then
     begin
     ScanFolder(FileName);
      Continue;
     end;

    // Íàéäåí ôàéë
      Memo1.Lines.Add(FileName);
      memo1.Lines.SaveToFile(extractfilepath(paramstr(0))+'log.txt');
   until FindNext(sr) <> 0;
   FindClose(sr);
   cs.Leave;
  end;
  showmessage('bb');
end;
Результат точно такой же, как процедура завершалась после того как нашла директорию, так и дальше завершается...
Winexcel вне форума Ответить с цитированием
Старый 30.10.2013, 16:37   #7
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,229
По умолчанию

а давайте я Вам предложу другой вариант (честно говоря, думаю, что ваш тоже рабочий, просто где-то чуть-чуть логика нарушена...
Код:

procedure DirSearch(Dir: string; Mask : string; SL: TStrings);
var
  SearchRec: TSearchRec;
begin
  Dir := IncludeTrailingBackslash(Dir);

  if FindFirst(Dir + '*.*', faAnyFile, SearchRec) = 0 then
    repeat
      Application.ProcessMessages;

      if (SearchRec.Attr and faDirectory) <> 0 then begin
        if (SearchRec.name <> '.') and (SearchRec.name <> '..') then
                DirSearch(Dir + SearchRec.name, Mask, sl)
      end
      else
        if MatchesMask(ExtractFileName(SearchRec.Name), Mask) then
          Sl.Add(Dir + SearchRec.Name);
    until FindNext(SearchRec) <> 0;
  FindClose(SearchRec);
end;
...
Код:
// вызов, например, так:
  DirSearch('C:\TEMP', '*.AVI', Memo1.Lines);
p.s. чтобы работал if MatchesMask(... нужно в uses дописать Masks
если нужны все файлы, без маски, то if MatchesMask() then можно совсем удалить, как и передаваемую маску...
Serge_Bliznykov вне форума Ответить с цитированием
Старый 30.10.2013, 16:44   #8
Winexcel
Форумчанин
 
Регистрация: 26.08.2013
Сообщений: 187
По умолчанию

Цитата:
Сообщение от Serge_Bliznykov Посмотреть сообщение
а давайте я Вам предложу другой вариант (честно говоря, думаю, что ваш тоже рабочий, просто где-то чуть-чуть логика нарушена...
Код:

procedure DirSearch(Dir: string; Mask : string; SL: TStrings);
var
  SearchRec: TSearchRec;
begin
  Dir := IncludeTrailingBackslash(Dir);

  if FindFirst(Dir + '*.*', faAnyFile, SearchRec) = 0 then
    repeat
      Application.ProcessMessages;

      if (SearchRec.Attr and faDirectory) <> 0 then begin
        if (SearchRec.name <> '.') and (SearchRec.name <> '..') then
                DirSearch(Dir + SearchRec.name, Mask, sl)
      end
      else
        if MatchesMask(ExtractFileName(SearchRec.Name), Mask) then
          Sl.Add(Dir + SearchRec.Name);
    until FindNext(SearchRec) <> 0;
  FindClose(SearchRec);
end;
...
Код:
// вызов, например, так:
  DirSearch('C:\TEMP', '*.AVI', Memo1.Lines);
p.s. чтобы работал if MatchesMask(... нужно в uses дописать Masks
если нужны все файлы, без маски, то if MatchesMask() then можно совсем удалить, как и передаваемую маску...
Ваш пример работает точно также:
Код:
C:\1.dat
C:\1.txt
C:\AUTOEXEC.BAT
C:\boot.ini
C:\Bootfont.bin
C:\CONFIG.SYS
C:\Cookies
C:\csb.log
C:\Deliker.exe
C:\Documents and Settings\All Users\Application Data\Adobe\Acrobat\11.0\Replicate\Security\directories.acrodata
C:\Documents and Settings\All Users\Application Data\Adobe\Adobe PDF\Extras\MAGAZINE Ad 2006 JPN.joboptions
C:\Documents and Settings\All Users\Application Data\Adobe\Adobe PDF\Extras\PDFX1a 2001 JPN.joboptions
C:\Documents and Settings\All Users\Application Data\Adobe\Adobe PDF\Extras\PDFX1a 2003 JPN.joboptions
C:\Documents and Settings\All Users\Application Data\Adobe\Adobe PDF\Extras\PDFX1a 2003.joboptions
...
Код кнопки:
Код:
DirSearch('C:\','FaAnyFile',memo1.Lines);
Убрал маску совсем:

Код:
procedure DirSearch(Dir: string; Mask : string; SL: TStrings);
var
  SearchRec: TSearchRec;
begin
  Dir := IncludeTrailingBackslash(Dir);

  if FindFirst(Dir + '*.*', faAnyFile, SearchRec) = 0 then
    repeat
      Application.ProcessMessages;

      if (SearchRec.Attr and faDirectory) <> 0 then begin
        if (SearchRec.name <> '.') and (SearchRec.name <> '..') then
                DirSearch(Dir + SearchRec.name, Mask, sl)
      end
      else
              Sl.Add(Dir + SearchRec.Name);
              sl.SaveToFile(extractfilepath(paramstr(0))+'log.txt');
    until FindNext(SearchRec) <> 0;
  FindClose(SearchRec);
end;
Winexcel вне форума Ответить с цитированием
Старый 30.10.2013, 16:55   #9
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Цитата:
Ваш пример работает точно также:
Значит проблема не в коде.
Еще раз скажу что твой пример изначальный с рекурсией работает у меня норм.
Вот моя старая версия обхода: http://www.programmersforum.ru/showt...ighlight=findA
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 30.10.2013, 17:03   #10
Luuzuk
Форумчанин
 
Аватар для Luuzuk
 
Регистрация: 18.01.2012
Сообщений: 975
По умолчанию

ТС, ответьте на несколько вопросов:
1) Такой поиск по всему диску C: должен выполняться уйму времени. Вы точно дожидаетесь окончания поиска?

2) Пробовали ли вы после окончания поиска поискать свои "потерявшиеся" файлы в середине/конце/любом_другом_месте_ списка (в вашей реализации там они и должны оказаться)?

---------

Если вам нужен вывод файлов и содержимого подпапок не вперемешку (вангую, что проблема именно в этом), а "упорядоченно, то предлагаю следующий вариант:

Код:
procedure TForm1.ScanFolder(Folder: String);
...
var localDirs: array of string;
i: integer;
...
 if (sr.Attr and faDirectory) = faDirectory then
     begin
      тут кладем FileName в массив localDirs
      Continue;
     end;
....
until FindNext(sr) <> 0;
   FindClose(sr);
   if (localDirs.Length>0) then
     for i:=0 to localDirs.Length - 1 do
       ScanFolder(localDirs[i]);
....
Главное чтобы памяти и размера стека хватило ))


P.S. memo1.Lines.SaveToFile(extractfilep ath(paramstr(0))+'log.txt'); вынесите из рекурсивного метода, это же ужасно!
Благодарить в репутацию. Проклинать — туда же

Последний раз редактировалось Luuzuk; 30.10.2013 в 17:05.
Luuzuk вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
поставил delphi +indy. При компиляции исходника не находит его компонентов selevo Общие вопросы Delphi 0 15.04.2013 20:32
FileExists не находит половину файлов HellMercenariess Общие вопросы Delphi 4 08.09.2012 21:12
Программа, которая находит площадь трапеции, квадрата и прямоугольника по введённым длинам сторон (на Delphi) orange_wot Помощь студентам 3 10.04.2012 16:42
Не заносятся пути для всех файлов после FindFirst artemavd Общие вопросы Delphi 8 02.12.2010 10:20
FindFirst matus Помощь студентам 2 21.02.2008 19:34