Программный поиск файлов

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Программный поиск файлов

Сообщение the_beginer » 05.07.2008 18:37:49

программно ищем файл, название которого пишем в edit1, результат выводим в edit2

Код: Выделить всё
var
  Form1: TForm1;
  b : boolean;
     
implementation

{ TForm1 }
procedure TForm1.FindFile(dir, conffile:String);
Var fs : TSearchRec;
     
begin

findfirst(dir + '/*',faAnyFile,fs);
repeat
  if (fs.Name='.') or (fs.Name='..') then continue;

  if (fs.Name='dev') then continue;
  if (fs.Name='home') then continue;
  if (fs.Name='mnt') then continue;

  if (fs.Attr and faDirectory) <> 0
     then findfile(dir + '/' + fs.name, conffile);

  if conffile = fs.Name
     then begin
            edit2.Text := dir + '/' + fs.Name;
            b := true;
          end;
  if b then exit;
until findnext(fs) <> 0;
end;



procedure TForm1.Button1Click(Sender: TObject);
begin
b := false;
FindFile('', edit1.Text);
showmessage('поиск окончен');
end;   


это все в принципе работает, но!
теперь собственно вопрос:
1.Я не просто так игнорирую папки home и mnt. Почему-то если искать и в этих каталогах, поиск файла дает ВСЕГДА отрицательный результат. Даже если искомый файл находится ну например в каталоге /etc.

Я грешил на то, что вся проблема в том, что в каталога home и mnt есть файлы с русскими буквами в названиях.
Однако, чуть позже выяснил, что поиск глючит, если еще искать в каталоге /dev Но в /dev кириллицей и не пахнет!

Уважаемый all,
подскажите в чем загвоздка?

кстати, запускаем программу под рутом
the_beginer
новенький
 
Сообщения: 30
Зарегистрирован: 29.05.2008 16:51:51

Re: Программный поиск файлов

Сообщение Padre_Mortius » 05.07.2008 19:00:14

Для начала стоит выровнять большие и маленькие буквы
Код: Выделить всё
if UpperСase(conffile) = UpperCase(fs.Name)


И также закрыть поиск с помощью FindClose

Добавлено спустя 33 минуты 2 секунды:
В качестве примера можно посмотреть по ссылке http://freepascal.ru/forum/viewtopic.php?f=13&t=3393&p=24063#p24063
Padre_Mortius
энтузиаст
 
Сообщения: 1265
Зарегистрирован: 29.05.2007 17:38:07
Откуда: Спб

Re: Программный поиск файлов

Сообщение the_beginer » 05.07.2008 20:07:52

впрочем, переписал процедуру поиска так
Код: Выделить всё
procedure TForm1.FindFile(dir, conffile:String);
Var fs : TSearchRec;
     s : string;
begin

findfirst(dir + '/*',faAnyFile,fs);
repeat
  if (fs.Name='.') then continue;
  if (fs.Name='..') then continue;
{
  if (fs.Name='dev') then continue;
}
  if (fs.Name='home') then continue;
  if (fs.Name='mnt') then continue;

  if (fs.Attr and faDirectory) <> 0
     then begin
           s := fs.name;
           findfile(dir + '/' + s, conffile);
          end;
         
  if conffile = fs.Name
     then begin
            edit2.Text := dir + '/' + fs.Name;
            b := true;
          end;
         
  if b
     then begin
            findclose(fs);
            exit;
          end;
         
until findnext(fs) <> 0;
findclose(fs);
end;


и получил, вот такой ответ в edit2.text:
/dev/fd/21/dev/fd/21/dev/fd/21/dev/fd/21/dev/fd/21/dev/fd/21/dev/fd/21/dev/fd/21
/dev/fd/21/dev/fd/21/dev/fd/21/dev/fd/21/dev/fd/21/dev/fd/21/dev/fd/21/dev/fd/21
/dev/fd/21/dev/fd/21/dev/fd/21/dev/fd/21/dev/fd/21/dev/fd/21/dev/fd/21/dev/fd/21
/dev/fd/21/dev/fd/21/etc/lilo.conf

все одной строкой

все таки поиск в /dev нада исключать, но почему?
the_beginer
новенький
 
Сообщения: 30
Зарегистрирован: 29.05.2008 16:51:51

Re: Программный поиск файлов

Сообщение Brainenjii » 05.07.2008 20:47:24

куча ссылок внутри /dev на себя же?
Аватара пользователя
Brainenjii
энтузиаст
 
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Re: Программный поиск файлов

Сообщение Padre_Mortius » 07.07.2008 09:05:00

количество /dev/fd/21 обозначает количество вхождений в эту папку

Добавлено спустя 3 часа 27 минут 23 секунды:
Код: Выделить всё
procedure TForm1.FindFile(dir, conffile:String);
var
  fs : TSearchRec;
  s : string;
begin
  findfirst(dir + '/*',faAnyFile,fs);
  repeat
    if (fs.Name<>'.') and (fs.Name<>'..') then
      if (fs.Attr and faDirectory) <> 0 then
      begin
        s := fs.name;
        findfile(dir + '/' + s, conffile);
      end else
        begin
          if conffile = fs.Name then
          begin
            edit2.Text := dir + '/' + fs.Name;
            b:= true;
            Exit;
          end;
        end;
    Form1.Caption := fs.Name;
    Application.ProcessMessages;
    if b then exit;
  until findnext(fs) <> 0;
  findclose(fs);
end;


Попробуй вот так. у меня нормально отработало.
Padre_Mortius
энтузиаст
 
Сообщения: 1265
Зарегистрирован: 29.05.2007 17:38:07
Откуда: Спб

Re: Программный поиск файлов

Сообщение the_beginer » 08.07.2008 12:14:30

Padre_Mortius писал(а):
Попробуй вот так. у меня нормально отработало.


и твой и мой код рабочие.но проблема осталась

покопался я тут и нашел странную вещь:

у меня есть каталог /usr/share/icons/mdk-hicolor, в котором есть линк normal на /usr/share/icons

так вот поиск отработав каталог /usr/share/icons/mdk-hicolor попадает на этот линк и вновь работает с каталогом /usr/share/icons/mdk-hicolor но уже под названием /usr/share/icons/mdk-hicolor/normal/mdk-hicolor. Там вновь попадает на линк и снова работает с нашим каталогом но уже под названием /usr/share/icons/mdk-hicolor/normal/mdk-hicolor/normal/mdk-hicolor.

Т.е. фактически зацикливается. C /dev походу та же проблема

Пытался обойти эту проблему так:
Код: Выделить всё
     if (fs.Attr and fasymlink) <> 0   then continue;


но это не сработало! После небольшого исследования обнаружил, что атрибут каталога и линка на каталог одинаковый (у меня равен fs.attr = 48, где fs : TSearchRec). Другими словами не делается различия между каталогом и линком на каталог. С файлом и линком на файл та же байда.

как дать понять программе, что перед нами линк на каталог, а не каталог?
Последний раз редактировалось the_beginer 08.07.2008 19:01:38, всего редактировалось 1 раз.
the_beginer
новенький
 
Сообщения: 30
Зарегистрирован: 29.05.2008 16:51:51

Re: Программный поиск файлов

Сообщение B4rr4cuda » 08.07.2008 13:12:35

the_beginer писал(а):как дать понять программе, что перед нами линк на каталог, а не каталог?

Код: Выделить всё
if FPS_ISLNK(fs.Attr) then continue;

Не забываем добавить BaseUnix в uses.
Аватара пользователя
B4rr4cuda
энтузиаст
 
Сообщения: 693
Зарегистрирован: 28.12.2007 07:48:35

Re: Программный поиск файлов

Сообщение the_beginer » 08.07.2008 13:32:50

B4rr4cuda писал(а):
the_beginer писал(а):как дать понять программе, что перед нами линк на каталог, а не каталог?

Код: Выделить всё
if FPS_ISLNK(fs.Attr) then continue;

Не забываем добавить BaseUnix в uses.



при всем уважении - не работает
Код: Выделить всё
uses .... , BaseUnix;

procedure TForm1.FindFilo (dir:String);
Var fs : TSearchRec;
begin

findfirst(dir + '/*',faAnyFile,fs);
repeat
  if (fs.Name='.') or (fs.Name='..') then continue;

if FPS_ISLNK(fs.Attr) = true
    then listbox1.Items.Add('==link==' + fs.name)
     else listbox1.Items.Add('=folder=' + fs.name);
     
until findnext(fs) <> 0;
findclose(fs);
end;   


всё показывает как =folder=, хотя есть один линк
Последний раз редактировалось the_beginer 08.07.2008 14:29:29, всего редактировалось 1 раз.
the_beginer
новенький
 
Сообщения: 30
Зарегистрирован: 29.05.2008 16:51:51

Re: Программный поиск файлов

Сообщение Alexx2000 » 08.07.2008 14:13:13

Если использовать функцию FPS_ISLNK, то надо делать вот так:
Код: Выделить всё
if FPS_ISLNK(fs.Mode) then continue;
Аватара пользователя
Alexx2000
постоялец
 
Сообщения: 488
Зарегистрирован: 25.10.2006 00:22:07
Откуда: Мытищи

Re: Программный поиск файлов

Сообщение the_beginer » 08.07.2008 14:24:26

Alexx2000 писал(а):Если использовать функцию FPS_ISLNK, то надо делать вот так:
if FPS_ISLNK(fs.Mode) then continue;


исправил на
Код: Выделить всё
if FPS_ISLNK(fs.mode) = true
    then listbox1.Items.Add('==link==' + fs.name)
     else listbox1.Items.Add('=folder=' + fs.name);

не-а, не работает
всё показывает как =folder=
the_beginer
новенький
 
Сообщения: 30
Зарегистрирован: 29.05.2008 16:51:51

Re: Программный поиск файлов

Сообщение B4rr4cuda » 08.07.2008 15:23:07

Таки да. Неладно в датском королевстве...
Этот вариант у меня работает:
Код: Выделить всё
procedure FindFilo (dir:String);
Var fs : TSearchRec; fst:Stat;
begin
findfirst(dir + '/*',faAnyFile,fs);
repeat
  if (fs.Name='.') or (fs.Name='..') then continue;

if fpReadLink(dir+'/'+fs.Name)<>''
    then form1.listbox1.Items.Add('==link==' + fs.name+' '+fpReadLink(dir+'/'+fs.Name))
     else form1.listbox1.Items.Add('=folder=' + fs.name);

until findnext(fs) <> 0;
findclose(fs);
end;
Аватара пользователя
B4rr4cuda
энтузиаст
 
Сообщения: 693
Зарегистрирован: 28.12.2007 07:48:35

Re: Программный поиск файлов

Сообщение the_beginer » 08.07.2008 15:45:19

хех, вот в чем сила интернета

заработала ! :)

Пасиба!
the_beginer
новенький
 
Сообщения: 30
Зарегистрирован: 29.05.2008 16:51:51

Re: Программный поиск файлов

Сообщение B4rr4cuda » 08.07.2008 16:10:05

Нема за шо. %)
Аватара пользователя
B4rr4cuda
энтузиаст
 
Сообщения: 693
Зарегистрирован: 28.12.2007 07:48:35

Re: Программный поиск файлов

Сообщение the_beginer » 08.07.2008 16:55:03

итак подводя итоги - программный поиск фалов (а также каталогов или линков)
---------------------------------------------------------------------------------------------------

Код: Выделить всё
uses ... , BaseUnix;

  .......

var
  Form1: TForm1;
  b : boolean;
  ffile : string;
 
  ......

procedure TForm1.FindFile(dir, conffile:String);
Var fs : TSearchRec;
begin
if dir = '/' then dir := '';
findfirst(dir + '/*',faAnyFile,fs);
repeat
  application.ProcessMessages;
  if (fs.Name='') or(fs.Name='.') or (fs.Name='..') then continue;
                                                                //(fs.Name='') включать обязательно,

  if conffile = fs.Name                //проверку на совпадение проводим сразу
     then begin                            //возможно мы ищем каталог или ссылку
            ffile := dir + '/' + fs.Name;
            b := true;
          end;

  if b
     then begin
            findclose(fs);
            exit;
          end;

  if fpReadLink(dir+ '/' +fs.Name) <> '' then continue;    //если линк, то пропускаем,
                                                                                 //чтобы избежать циклических ссылок

  if ((fs.Attr and faDirectory) <> 0)                  //если каталог,
     then findfile(dir + '/' + fs.name, conffile);  //то запускаем эту же функцию,
                                                                    //но с новым каталогом



until findnext(fs) <> 0;
findclose(fs);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
b := false;
FindFile(edit1.Text, edit2.Text); //1-параметр - путь поиска, 2-ой - имя искомого
edit3.Text := ffile;                     //результаты поиска - полный путь и название файла
showmessage('поиск окончен');
end;


---------------------------------------------------------------------------------------------------

классика! В FAQ, однозначно :)
the_beginer
новенький
 
Сообщения: 30
Зарегистрирован: 29.05.2008 16:51:51

Re: Программный поиск файлов

Сообщение Padre_Mortius » 08.07.2008 18:08:16

Для FAQ имхо лучше убрать continue, т.к. очень близко к label и goto. Да и читабельность кода будет лучше
Padre_Mortius
энтузиаст
 
Сообщения: 1265
Зарегистрирован: 29.05.2007 17:38:07
Откуда: Спб

След.

Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: Google [Bot] и гости: 40

Рейтинг@Mail.ru