Программный поиск файлов на Delphi (исходники)Источник: DeVoid DeVoid
В этом уроке мы с вами ознакомимся с основными принципами программной организации поиска файлов. Для начала определимся, зачем нам это может быть нужно. Например, вам нужно при запуске программы на выполнение просканировать определенный каталог на присутствие DOC файлов, и при наличии таковых открыть их на редактирование или напечатать. А как вам такая идея: фоновый поиск EXE файла в сети, и при обнаружении новой версии, автоматическое обновление.
Вспомним правила поиска файлов. Вы можете задать как имя искомого файла, так и его маску, если название неизвестно или необходимо найти несколько. Т.е. применяя специальный шаблон поиска, вы можете организовать условия выборки найденных файлов. Сразу оговорюсь, что поиск можно применять как к файлам, так и к каталогам. Будем их называть элементами файловой системы. В шаблон маски искомых элементов может входить:
Например, вы ищите все текстовые файлы с расширением TXT. В поле имени искомого файла вам нужно ввести "*.TXT" (пишется без кавычек) и система найдет все такие файлы в указанном диске или каталоге. Если вам надо найти все файлы с названием semen, то в поле поиска файла нужно ввести "semen.*". Если вам нужно найти элементы с третьей буквой k и с первой буквой t в расширении, то вводите "??k*.t*". Здесь знак вопроса указывает на любой символ, третьим символом по порядку идет буква k, далее название файла (каталога) может состоять из любого количества букв и цифр, указываем звездочку. В расширении первая буква t, дальше следует любое расширение. Теперь рассмотрим программный поиск файлов с помощью языка программирования object pascal. Вся организация цикла поиска, а именно это и есть цикл с продолжением поиска, сводится к:
Функция FindFirstСинтаксис: FindFirst (КАТАЛОГ_ПОИСКА_И_МАСКА_ФАЙЛА, АТРИБУТЫ_ИСКОМОГО_ФАЙЛА , ПОИСКОВОЯ_ПЕРЕМЕННАЯ); где: Каталог для поиска и маска искомого элемента - строковая величина, имеющая тип String, может, например, содержать 'c:\*.*' - все элементы в корне диска С. Обратите внимание, что указывается полный путь для поиска. Атрибуты искомого элемента это пользовательские или системные атрибуты, которые может иметь файл (каталог, метка диска). Вот их перечень:
Если вам нужно искать только элементы, имеющие атрибут "каталог" и "скрытый", то можно применить знак математического сложения, например faDirectory + faHidden. Поисковая переменная имеет тип TSearchRec. В нее, при успешном результате поиска, будет занесены все необходимые данные о найденном файловом элементе. Поскольку FindFirst является функцией, то она должна сама возвращать некоторое значение. Это значение имеет тип Integer и означает результат поиска файла (код ошибки поиска). Если файл найден, то принимает нулевое значение. Функция FindNextFindNext ( ПОИСКОВАЯ_ПЕРЕМЕННАЯ ); Эта функция продолжает поиск, заданный в функции FindNext. Возвращает значение результата поиска (нулевое в случае успешного поиска). Процедура FindCloseFindClose ( ПОИСКОВАЯ_ПЕРЕМЕННАЯ ); Закрывает поиск и освобождает память, выделенную системой под поиск. Теперь рассмотрим пример. Допустим, нам надо найти все файлы и каталоги в каталоге DELPHI, находящийся на диске C:. В дальнейшем, вы можете самостоятельно, изменяя маску, менять условия поиска. Для формы с компонентом ListBox1 и кнопкой Button1 реакция на OnClick по кнопке: procedure TForm1.Button1Click(Sender: TObject); Var SR:TSearchRec; // поисковая переменная FindRes:Integer; // переменная для записи результата поиска begin ListBox1.Clear; // очистка компонента ListBox1 перед занесением в него списка файлов FindRes:=FindFirst('c:\delphi\*.*',faAnyFile,SR); // задание условий поиска и начало поиска While FindRes=0 do // пока мы находим файлы (каталоги), то выполнять цикл begin ListBox1.Items.Add(SR.Name); // добавление в список название найденного элемента FindRes:=FindNext(SR); // продолжение поиска по заданным условиям end; FindClose(SR); // закрываем поиск end; Представленный пример кода, в принципе, является основой для организации более углубленного поиска, поиска файлов по времени создания, по содержащимся словам. Если вы запустите эту программу на выполнение, то при нажатии на кнопку Button1 вы увидите в списке в первой и второй строке элементы "." и "..". Это элементы, имеющие атрибут "каталог". Первый содержит связь с корневым каталогом диска, второй содержит связь к каталогом верхнего уровня. Со вторым вы встречаетесь в дисковых командных оболочках, например нортон, когда выбираете каталог ".." и нажимаете на "ввод". Тем самым вы попадаете в каталог на уровень выше. Естественно, в нашей поисковой программе такие элементы не надо вносить в список, поэтому мы игнорируем их нахождение. Исправляем процедуру нажатия на кнопку Button1: procedure TForm1.Button1Click(Sender: TObject); Var SR:TSearchRec; FindRes:Integer; begin ListBox1.Clear; FindRes:=FindFirst('c:\delphi\*.*',faAnyFile,SR); While FindRes=0 do begin if ((SR.Attr and faDirectory)=faDirectory) an d // если найденный элемент каталог и ((SR.Name='.')or(SR.Name='..')) then // он имеет название "." или "..", тогда: begin FindRes:=FindNext(SR); // продолжить поиск Continue; // продолжить цикл end; ListBox1.Items.Add(SR.Name); FindRes:=FindNext(SR); end; FindClose(SR); end; В этом случае, при нахождении каталога с именем "." или с именем ".." программа продолжит обработку цикла поиска без вывода найденного имени элемента в компонент списка ListBox1. Теперь рассмотрим тип TSearchRec. Он имеет в себе несколько полезных свойств:
Все вышеперечисленные свойства мы уже рассмотрели или они понятны сразу, за исключением свойства Time. Оно имеет тип Integer и содержит в себе упакованное значение даты и времени создания файла. Распаковка производится с помощью функции FileDateToDateTime, которая в результате возвращает значение даты и времени. procedure TForm1.Button1Click(Sender: TObject); Var SR:TSearchRec; FindRes:Integer; begin ListBox1.Clear; FindRes:=FindFirst('c:\delphi\*.*',faAnyFile,SR); While FindRes=0 do begin if ((SR.Attr and faDirectory)=faDirectory) and ((SR.Name='.')or(SR.Name='..')) then begin FindRes:=FindNext(SR); Continue; end; if FileDateToDateTime(SR.Time)<DateTimePicker1.Date then // если у файла (каталога) дата создания меньше, чем установлено в DateTimePicker1, то begin FindRes:=FindNext(SR); // продолжить поиск Continue; // продолжить цикл end; ListBox1.Items.Add(SR.Name); FindRes:=FindNext(SR); end; FindClose(SR); end; Как вы уже заметили, мы отбираем файлы и каталоги по дате создания, начиная с указанной в компоненте DateTimePicker1. Теперь попробуем организовать поиск файлов во всех вложенных каталогах. Это не так просто, как может показаться на первый взгляд. Нам придется вручную организовывать весь цикл входа-выхода из каталога, перебор файлов. Немного сложноватый материал, но возможно те из вас, кто уже работал с языком программирования pascal или другим, знакомы с технологией многократности и многовложенности использования одного и того же программного кода. Коротко объясню алгоритм работы такой программы.
Таким образом, сколько витков программа наматывает на так называемый клубок, столько витков она и размотает. Программа на выполнении проходит все дерево вложенных каталогов, выполняя один и тот же кусок программного кода! И при этом данные условий поиска не перепутываются, и для каждой уникальной процедуры они сохраняются. Рассмотрим пример. Создайте новый проект. Для создания отдельной процедуры поиска нам нужно объявить ее в соответствующем разделе (создаем ее вручную, поэтому и самостоятельно объявляем). В разделе public пишем строку: procedure FindFile(Dir:String); А в разделе кода программы, до слова "end." вставляем пустой каркас процедуры procedure TForm1.FindFile(Dir:String); begin end; На форму вставляем компонент списка ListBox1, Button1, Edit1. Для компонента Edit1 свойство Text устанавливаем в "c:\delphi\". Обратите внимание на последний символ, знак "\", присутствие которого в начальном пути поиска обязательно. Дальше процедура OnClick для кнопки Button1 выглядит следующим образом: procedure TForm1.Button1Click(Sender: TObject); begin ListBox1.Clear; // очистка списка файлов FindFile(Edit1.Text); // поиск файлов с начальными условиями, заданных в Edit1 end; Созданная нами вручную процедура поиска: procedure TForm1.FindFile(Dir:String); Var SR:TSearchRec; FindRes:Integer; begin FindRes:=FindFirst(Dir+'*.*',faAnyFile,SR); While FindRes=0 do begin if ((SR.Attr and faDirectory)=faDirectory) and ((SR.Name='.')or(SR.Name='..')) then begin FindRes:=FindNext(SR); Continue; end; if ((SR.Attr and faDirectory)=faDirectory) then // если найден каталог, то begin FindFile(Dir+SR.Name+'\'); // входим в процедуру поиска с параметрами текущего каталога + каталог, что мы нашли FindRes:=FindNext(SR); // после осмотра вложенного каталога мы продолжаем поиск в этом каталоге Continue; // продолжить цикл end; ListBox1.Items.Add(SR.Name); FindRes:=FindNext(SR); end; FindClose(SR); end; Если вы в компоненте Edit1 в качестве начального условия поиска файлов зададите корневую папку диска, например "С:\", то вы получите полный перечень всех файлов на данном диске. Обратите внимание на скорость поиска файлов и скорость работы вашей программы. |