Электронная библиотека » Александр Чиртик » » онлайн чтение - страница 8


  • Текст добавлен: 10 ноября 2013, 00:08


Автор книги: Александр Чиртик


Жанр: Программирование, Компьютеры


сообщить о неприемлемом содержимом

Текущая страница: 8 (всего у книги 24 страниц)

Шрифт:
- 100% +
Имена временных файлов

Для централизованного хранения временных данных, необходимых при работе приложений, в Windows предусмотрена специальная папка Temp. Ее расположение может изменяться. Причем в многопользовательских версиях Windows (NT, 2000, XP) местоположение папки для временных файлов может быть различным для различных пользователей. Итак, расположение папки Temp можно определить с помощью API-функции GetTempPath. Это функция принимает строковый буфер и длину этого буфера и возвращает количество символов, записанных в переданную строку, или 0, если возникла ошибка. Функция-оболочка, скрывающая работу со строковым буфером и преобразование типов, реализуется аналогично двум ранее рассмотренным функциям (листинг 4.12).

Листинг 4.12. Определение расположения папки временных файлов

function GetTempDir(): String;

var

buffer: String;

len: UINT;

begin

SetLength(buffer, MAX_PATH + 1);

len:= GetTempPath(MAX_PATH, PAnsiChar(buffer));

SetLength(buffer, len);

GetTempDir:= buffer;

end;

Кроме того, Windows API предусматривает очень полезную функцию, избавляющую программиста от необходимости подбирать имена временным файлам так, чтобы они были уникальными в пределах заданной папки (это не обязательно должна быть папка Temp). Имя этой функции – GetTempFileName. Пример ее использования приведен в листинге 4.13.

Листинг 4.13. Определение имени временного файла

function GetTempFile (prefix: String= '~mytmp'): String;

var

buffer, dir: String;

begin

dir:= GetTempDir();

//Получение имени временного файла (система сама определяет имя,

//уникальное для заданной папки)

SetLength(buffer, MAX_PATH + 1);

GetTempFileName(PAnsiChar(dir), PAnsiChar(prefix), 0, PAnsiChar(buffer));

GetTempFile:= buffer;

end;


Приведенная в листинге 4.13 функция в качестве папки временных файлов использует папку Temp, однако функцию GetTempFileName можно использовать для получения имен файлов в пределах любой папки.

Кроме пути папки, в которой необходимо создать временный файл, функция GetTempFileName принимает строку-префикс для имени временного файла и целочисленное значение (третий параметр). Если третий параметр не равен нулю, то его значение в шестнадцатеричной форме просто прибавляется справа к строке prefix. Никаких проверок на уникальность получившегося имени файла при этом не производится. Если же третьему параметру присвоить значение 0, то система сама сформирует шестнадцатеричное значение так, чтобы имя файла было уникальным в заданной папке. При этом, кроме того, создается и сам файл.

Буфер (последний параметр функции GetTempFileName) должен вмещать как минимум MAX_PATH символов, так как функция записывает в него полный путь временного файла.

Пример работы функций определения папки временных файлов, получения имени для временного файла, а также определения системных папок Windows показан на рис. 4.2.

Рис. 4.2. Расположения папок WINDOWS, system, Temp и имя для временного файла

Определение прочих системных путей

В Windows существует ряд других системных путей, которые так или иначе могут пригодиться. Определяются они не менее просто, чем пути к системным папкам (листинг 4.14).

Листинг 4.14. Определение прочих системных путей

function GetSpecialDir(dirtype: Integer): String;

var

buffer: String;

begin

SetLength(buffer, MAX_PATH + 1);

SHGetSpecialFolderPath(0, PAnsiChar(buffer), dirtype, False);

GetSpecialDir:= buffer;

end;


Здесь используется функция командной оболочки файловой системы (Windows Shell) SHGetSpecialFolderPath, объявление которой находится в модуле ShlObj. Среди параметров этой функции самыми значимыми (кроме буфера длиной минимум MAX_PATH символов для помещения в него пути) являются два последних параметра. Третий параметр функции SHGetSpecialFolderPath используется для указания папки, расположение которой необходимо определить. Если четвертый параметр функции SHGetSpecialFolderPath не равен False и запрашиваемой папки не существует, то папка будет создана.

Пример использования функции GetSpesialDir для составления списка (в элементе управления ListView) некоторых системных путей приведен в листинге 4.15. Из него вы также можете узнать имена целочисленных констант, идентифицирующих некоторые папки.

Листинг 4.15. Использование функции GetSpecialDir

procedure TForm3.Button1Click(Sender: TObject);

var

item: TListItem;

begin

lvwPathes.Clear;

//Определение путей некоторых системных папок

//..Рабочий стол

item:= lvwPathes.Items.Add();

item.Caption:= 'Рабочий стол';

 item.SubItems.Insert(0, GetSpecialDir(CSIDL_DESKTOPDIRECTORY));

//..Избранное

item:= lvwPathes.Items.Add();

item.Caption:= 'Избранное';

item.SubItems.Insert(0, GetSpecialDir(CSIDL_FAVORITES));

//..Шрифты

item:= lvwPathes.Items.Add();

item.Caption:= 'Шрифты';

item.SubItems.Insert(0, GetSpecialDir(CSIDL_FONTS));

//..Мои документы

item:= lvwPathes.Items.Add();

item.Caption:= ' Мои документы';

item.SubItems.Insert(0, GetSpecialDir(CSIDL_PERSONAL));

//..Последние документы

item:= lvwPathes.Items.Add();

item.Caption:= 'Последние документы';

item.SubItems.Insert(0, GetSpecialDir(CSIDL_RECENT));

//..История

item:= lvwPathes.Items.Add();

item.Caption:= 'История';

item.SubItems.Insert(0, GetSpecialDir(CSIDL_HISTORY));

//..Отправить

item:= lvwPathes.Items.Add();

item.Caption:= 'Отправить';

item.SubItems.Insert(0, GetSpecialDir(CSIDL_SENDTO));

//..Меню Пуск

item:= lvwPathes.Items.Add();

item.Caption:= 'Пуск';

item.SubItems.Insert(0, GetSpecialDir(CSIDL_STARTMENU));

//..Меню Программы

item:= lvwPathes.Items.Add();

item.Caption:= ' Программы';

item.SubItems.Insert(0, GetSpecialDir(CSIDL_PROGRAMS));

//..Меню 'Автозагрузка'

item:= lvwPathes.Items.Add();

item.Caption:= ' Авто загрузка ';

item.SubItems.Insert(0, GetSpecialDir(CSIDL_STARTUP));

//..Папка с шаблонами документов

item:= lvwPathes.Items.Add();

item.Caption:= 'Шаблоны';

item.SubItems.Insert(0, GetSpecialDir(CSIDL_TEMPLATES));

end;


Пример возможного результата выполнения процедуры, представленной в листинге 4.14, показан на рис. 4.3.

Рис. 4.3. Прочие системные пути Windows


В коде приведенной в листинге 4.15 процедуры определены не все пути, доступные с использованием функции SHGetSpecialFolderPath. Дело в том, что существует ряд виртуальных (не существующих реально на диске) папок: Мой компьютер, Принтеры, Сетевое окружение и т. д.

Для некоторых упоминаемых в листинге 4.15 папок существуют также аналогичные папки, содержимое которых доступно всем пользователям:

• CSIDL_COMMON_DESKTOPDIRECTORY – содержимое этой папки отображается на Рабочем столе всех пользователей;

• CSIDL_COMMON_DOCUMENTS – содержит общие документы;

• CSIDL_COMMON_FAVORITES – содержит общие элементы папки Избранное;

• CSIDL_COMMON_PROGRAMS – содержит общие для всех пользователей программы (пункт Программы меню "Пуск");

• CSIDL_COMMON_STARTMENU – содержит общие элементы, отображаемые в меню "Пуск";

• CSIDL_COMMON_STARTUP – содержит общие элементы меню Автозагрузка;

• CSIDL_COMMON_TEMPLATES – папка с общими для всех пользователей шаблонами документов.

Примечание

Большинство из перечисленных выше путей определяются только в системах Windows на ядре NT, но недоступны в Windows 95/98/Me.

Определение и установка текущей папки

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

Для определения текущей папки приложения используется функция GetCurrentDir, приведенная в листинге 4.16.

Листинг 4.16. Определение текущей папки

function GetCurrentDir(): String;

var

len: Integer;

buffer: String;

begin

SetLength(buffer, MAX_PATH + 1);

len:= GetCurrentDirectory(MAX_PATH, PAnsiChar(buffer));

GetCurrentDir:= Copy(buffer, 1, len);

end;


Функция определения пути текущей папки основана на применении соответствующей API-функции GetCurrentDirectory. Вполне естественно, что эта функция имеет себе пару – функцию для задания текущей папки SetCurrentDirectory. Объявление этой функции происходит следующим образом:


function SetCurrentDirectory(lpPathName: PChar): BOOL; stdcall;


Функция принимает путь папки и возвращает ненулевое значение в случае успешного своего выполнения.

Преобразование путей

Далее будет рассмотрено несколько функций, которые могут пригодиться, если возникнет необходимость преобразования путей. Имеется в виду прежде всего преобразование имен файлов в формат MS-DOS и обратно. Этот вид преобразования наглядно продемонстрирован на рис. 4.4 (верхняя часть формы).

Рис. 4.4. Преобразования путей


Иногда удобно представлять пути относительно какой-либо вложенной, а не корневой папки диска. Например, представьте, что вы разрабатываете приложение, документы которого, являющиеся неделимыми для пользователя, могут фактически состоять из большого количества файлов, расположенных в разных папках (Images, Movies, Embed и др.). Сами папки расположены в той же папке, что и основной файл документа или ниже по иерархии (во вложенных папках). Как добиться того, чтобы при копировании приложения со всеми нужными папками в другое место (на другой диск или компьютер, в другую папку) его по-прежнему можно было открыть, рассчитывая, что в папках Images, Movies и Embed содержится нужная информация. Для этого приложение должно «знать», какие файлы и в каких папках ему действительно необходимы. В таком случае пригодится относительный путь, который содержит в себе информацию о количестве и направлении переходов из папки, заданной в качестве корневой, чтобы можно было найти указанный в этом пути файл или папку.

Преобразование абсолютного пути в относительный и наоборот вы можете увидеть на рис. 4.4 (нижняя часть формы). Здесь в качестве исходного пути берется информация, содержащаяся в текстовом поле Исходный длинный путь, а в качестве пути папки для построения относительного пути – в текстовом поле Текущая папка.

На всякий случай стоит уточнить, что в относительном пути символ. указывает на текущую папку (никуда переходить не надо), а символ… означает папку, расположенную на один уровень выше (родительскую папку). Также следует уточнить, что под абсолютным путем понимается путь, корневым элементом которого является \ или <диск>:(C:, D: и т. д.).

Примечание

Все приведенные далее функции преобразования вы можете найти в модуле PathConvert, расположенном на диске, в папке с названием подраздела.

Преобразование длинных имен файлов в короткие, и наоборот

Теперь рассмотрим реализацию преобразования путей. Сначала – преобразование между длинной и короткой формами. Выполняется это предельно просто (благо Windows API предусматривает соответствующие функции).

Функция преобразования длинного пути в короткий приведена в листинге 4.17.

Листинг 4.17. Преобразование длинного пути в короткую форму

function LongPathToShort(path: String): String;

var

buffer: String;

len: Integer;

begin

SetLength(buffer, MAX_PATH);

len:= GetShortPathName(PAnsiChar(path), PAnsiChar(buffer), MAX_PATH);

SetLength(buffer, len);

LongPathToShort:= buffer;

end;


Соответственно, функция обратного преобразования пути может выглядеть следующим образом (листинг 4.18).

Листинг 4.18. Преобразование пути из короткой в длинную форму

function ShortPathToLong(path: String): String;

var

buffer: String;

len: Integer;

begin

SetLength(buffer, MAX_PATH);

len:= GetLongPathName(PAnsiChar(path), PAnsiChar(buffer), MAX_PATH);

SetLength(buffer, len);

ShortPathToLong:= buffer;

end


При тестировании последнего листинга в Delphi 7 выяснилось, что API-функция GetLongPathName объявлена в модуле Windows. Возможно, в других версиях Delphi это не так, но, в любом случае, импортировать эту функцию из библиотеки Kernel32. dll предельно просто – достаточно поместить в модуль следующую строку:


function GetLongPathName(lpszLongPath: PChar; lpszShortPath: PChar;

cchBuffer: DWORD): DWORD; stdcall;

external kernel32 name 'GetLongPathNameA';


Преобразование абсолютного пути в относительный, и наоборот

Теперь пришла очередь рассмотреть реализацию преобразований между абсолютной и относительной формами путей. Однако сначала рассмотрим небольшую, но полезную процедуру, используемую при преобразованиях. Процедура GetPathElements (листинг 4.19) формирует список строк из компонентов переданного ей пути (имен папок и именицелевого файла или папки).

Листинг 4.19. Разбиение пути на составляющие

procedure GetPathElements(path: String; elements: TStrings);

var

start, pos: Integer;

begin

start:= 1;

for pos:= 1 to Length(path) do

if path [pos] = '' then

begin

if start <> pos then

//Выделим имя папки

elements.Add(Copy(path, start, pos – start))

else

//Сочетание типа '\' в середине пути пропускаем

;

start:= pos + 1;

end;

pos:= Length(path) + 1;

if start <> pos then

//Выделим имя последней папки или файла

elements.Add(Copy(path, start, pos – start));

end;


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

Функция преобразования абсолютного пути в относительный (относительно заданной в параметре curdir папки) приведена в листинге 4.20.

Листинг 4.20. Преобразование абсолютного пути в относительный

function AbsPathToRelative(path, curdir: String): String;

var

pathElements, curElements: TStrings;

outPath: String;

i, j: Integer;

begin

if Copy(path, 1, 2) <> Copy(curdir, 1, 2) then

begin

//Папки на разных дисках

AbsPathToRelative:= path;

Exit;

end;

//Получение составляющих абсолютного и текущего пути

pathElements:= TStringList.Create;

GetPathElements(path, pathElements);

curElements:= TStringList.Create;

GetPathElements(curdir, curElements);

//Пропускаем одинаковые папки

i:= 0;

while (i < curElements.Count) and (i < pathElements.Count)

and (CompareText(curElements[i], pathElements[i]) = 0) do Inc(i);

//Добавляем небходимое количество переходов вверх для того, чтобы из

//папки curdir попасть в общую для path и curdir папку

for j:= i to curElements.Count -1 do

out Path:= out Path + '..';

//Заходим из папки полученной (общей) в папку path

for j:= i to pathElements.Count – 2 do

out Path:= out Path + path Elements[j] + '';

//Последним добавляем имя конечной папки или файла

AbsPathToRelative:= outPath + pathElements[pathElements.Count – 1];

//Списки строк больше не нужны

pathElements.Free;

curElements.Free;

end;


При преобразовании нужно учитывать, что пути, не принадлежащие одной иерархии (например, локальный и сетевой пути или пути, принадлежащие разным дискам), не могут быть представлены один относительно другого: у них нет общей родительской папки.

Функция обратного преобразования относительного пути в абсолютный приведена в листинге 4.21. Здесь нужно отметить, что если путь папки curdir относительный, то в итоге получается также относительный путь (относительно другой папки). Поэтому функция и называется RelativePathToRelative, а не RelativePathToAbs.

Листинг 4.21. Преобразование относительного пути в абсолютный

function RelativePathToRelative(path, curdir: String): String;

var

pathElements, curElements: TStrings;

outPath: String;

i: Integer;

begin

//Получение списка составляющих абсолютного и текущего пути

pathElements:= TStringList.Create;

GetPathElements(path, pathElements);

curElements:= TStringList.Create;

GetPathElements(curdir, curElements);

//Изначально находимся в последней папке пути curdir

//"Путешествуем" от текущей папки вверх или вниз по дереву папок

//(прибавляя или удаляя компоненты пути из списка curElements)

for i:= 0 to pathElements.Count–1 do

begin

if pathElements[i] = '..' then

//Вверх по дереву

if (curElements.Count > 0)then

curElements.Delete(curElements.Count – 1)

else

curElements.Append('..')

else if pathElements[i] <> '.' then

//Вниз по дереву (знак текущей папки "." не изменяет положение)

curElements.Append(pathElements[i]);

end;

//Формируем результирующий путь

if (curElements.Count > 0) then outPath:= curElements[0];

for i:= 1 to curElements.Count -1 do

out Path:= out Path + ''+ curElements[i];

RelativePathToRelative:= outPath;

//Списки строк больше не нужны

pathElements.Free;

curElements.Free;

end;

Поиск

Поиск является неотъемлемой частью работы с файловой системой. Даже простой просмотр содержимого любой папки сопряжен с использованием простейших, но все же поисковых средств (перебор и, возможно, отсеивание элементов папки). Поэтому далее будут рассмотрены возможные варианты реализации двух функций поиска: поиска по маске и атрибутам файлов в пределах заданной папки и такого же поиска по всему дереву папок, начиная от заданной корневой папки. Все рассмотренные далее функции поиска можно найти в модуле Search, расположенном на диске, в папке с названием подраздела.

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

Маски и атрибуты

Маска имени файла или папки представляет собой строку, в которой неизвестный одиночный символ можно заменять символом? а произвольное количество (0 и более) неизвестных заранее символов можно заменять символом *. Остальные (допустимые в имени) символы обозначают сами себя. Например, имена файлов SomeFile.exe и Some.exe удовлетворяют каждой из масок: Some* и Some*.exe.

Атрибуты определяют некоторые важные особенности файла. Так, например, при просмотре папки с помощью API-функций папка может отличаться от файла только наличием атрибута FILE_ATTRIBURE_DIRECTORY. Вообще содержимое папки записано на диске в самый обычный файл. Его отличает наличие указанного неизменяемого вручную атрибута и строго заданный формат записей, а также наличие специальных функций, скрывающих все особенности работы с данными папки (открытие файла с записями, поиск нужных записей).

Теперь об атрибутах. Ниже приведен перечень наиболее часто используемых атрибутов файлов и папок (идентификаторы целочисленных констант, объявленных в модуле Windows) (если не сказано иного, атрибут можно изменить):

• FILE_ATTRIBUTE_ARCHIVE – архивный файл или папка (на опыте замечено, что этот атрибут появляется практически у всех файлов, находящихся на диске некоторое время);

• FILE_ATTRI BUTE_DI RECTORY – атрибут папки (атрибут нельзя самостоятельно снять или назначить);

• FILE_ATTRIBUTE_HIDDEN – скрытый файл или папка;

• FILE_ATTRIBUTE_NORMAL – означает отсутствие особых атрибутов у файла или папки (у папки, естественно, всегда установлен атрибут FILE_ATTRIBUTE_ DIRECTORY);

• FILE_ATTRIBUTE_READONLY – файл или папка, доступные только для чтения;

• FILE_ATTRIBUTE_SYSTEM – системный файл или папка;

• FILE_ATTRIBUTE_TEMPORARY – временный файл (для ускорения доступа к находящимся в нем данным файловая система стремится по возможности хранить все содержимое открытого временного файла в оперативной памяти).

Выше были рассмотрены основные атрибуты, которые могут быть присвоены объектам файловой системы (файлам и папкам), но не было сказано, как получить или установить атрибуты файла или папки. Атрибуты можно получить при просмотре содержимого папки (как в рассмотренных далее функциях поиска), а также с помощью API-функции GetFileAttributes. Эта функция принимает путь файла (PChar) и возвращает значение типа DWORD (32-битное целое значение), представляющее собой битовую маску. Если функция GetFileAttributes завершается неудачно, то возвращаемое значение равно $FFFFFFFF (-1 при переводе к беззнаковому целому).

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


var attrs: DWORD;

begin

attrs:= GetFileAtt ribut e(PAnsiChar('C:boot.ini'));

if (attrs and FILE_ATTRIBUTE_SYSTEM <> 0) then {файл системный};


Атрибуты устанавливаются с помощью API-функции SetFileAttributes. Данная функция принимает два параметра: путь файла или папки (PChar) и битовую маску атрибутов и возвращает ненулевое значение в случае успешного выполнения задачи и 0 (False) в противном случае.

Поскольку в функцию SetFileAttributes передается маска, хранящая сведения сразу обо всех атрибутах файла или папки, то изменять атрибуты нужно аккуратно (чтобы не удалить установленные ранее). Пример (отрывок программы) назначения одного и одновременного снятия другого атрибута файла приведен в листинге 4.22 (для простоты проверка ошибок не производится).

Листинг 4.22. Изменение атрибутов файла

var attrs: DWORD;

begin

attrs:= GetFileAttributes('C:text .txt');

attrs:= attrs or FILE_ATTRIBUTE_HIDDEN; //Установка атрибута "скрытый"

attrs:= attrs and not FILE_ATTRIBUTE_ARCHIVE; //Снятие атрибута "архивный"

SetFileAttributes('C:text.txt', attrs);


Поиск в указанной папке

Поиск в пределах одной папки представляет собой простой перебор всех ее элементов с отбором тех, имена которых удовлетворяют маске и заданному набору атрибутов. В приведенном ниже примере (листинг 4.23) используется API-функция FindFirstFile, которая начинает просмотр указанной папки, автоматически отсеивая имена файлов и папок, не удовлетворяющие маске, и возвращает дескриптор (THandle), используемый для идентификации начатого сеанса просмотра папки при продолжении поиска (передается в функции FindNextFile и FindClose).

После окончания просмотра папки вызывается функция FindClose, завершающая просмотр папки. Весь процесс очень напоминает работу с обычным файлом (открытие, просмотр, закрытие), не так ли?

Листинг 4.23. Поиск в заданной папке

function SearchInFolder(folder, mask: String; flags: DWORD;

names: TStrings; addpath: Boolean = False): Boolean;

var

hSearch: THandle;

FindData: WIN32_FIND_DATA;

strSearchPath: String;

bRes: Boolean; //Если равен True, то найден хотя бы один файл или папка

begin

strSearchPath:= folder + ''+ mask;

bRes:= False;

//Начинаем поиск

hSearch:= FindFirstFile(PAnsiChar(strSearchPath), FindData);

if (hSearch <> INVALID_HANDLE_VALUE) then

begin

//Ищем все похожие элементы (информация о первом элементе уже

//записана в FindData функцией FindFirstFile)

repeat

if (String(FindData.cFileName) <> '..') and

(String(FindData.cFileName) <> '.') then //Пропускаем . и ..

begin

if MatchAttrs(flags, FindData.dwFileAttributes) then

begin

//Нашли подходящий объект

if addpath then

names.Add(folder + ''+ FindData.cFileName)

else

names.Add(FindData.cFileName);

bRes:= True;

end;

end;

until FindNextFile(hSearch, FindData) = False;

//Заканчиваем поиск

FindClose(hSearch);

end;

SearchInFolderr r:= bRes;

end;


В результате работы функции SearchInFolder заполняется список names именами или, если значение параметра addpath равно True, полными путями найденных файлов и папок. Значение параметра flags (битовая маска атрибутов) формируется так же, как для функции SetFileAttributes, только одновременно могут быть установлены любые интересующие атрибуты. При обнаружении хотя бы одного файла или папки функция SearchlnFolder возвращает значение True.

В функции поиска проверка соответствия атрибутов найденных файлов и папок маске производится с помощью дополнительной функции MatchAttrs. Код этой функции приведен в листинге 4.24.

Листинг 4.24. Фильтр атрибутов

function MatchAttrs(flags, attrs: DWORD): Boolean;

begin

MatchAttrs:= (flags and attrs) = flags;

end;


Может показаться, что проверка из одной строки – недостаточная причина для создания отдельной функции. Тем не менее в рассматриваемом примере отдельная функция MatchAttrs выделена для того, чтобы сделать отсеивание файлов (и папок) по атрибутам более очевидным.

В листинге 4.24 приведена реализация нестрогого фильтра: он принимает файл или папку, если они имеют все установленные во flags атрибуты, независимо от того, имеет ли файл или папка дополнительные атрибуты. Так, если, например, задан flags:= FILE_ATTRIBUTE_READONLY, то будут найдены скрытые, системные и прочие как файлы, так и папки, имеющие среди своих атрибутов атрибут FILE_ATTRIBUTE_READONLY. Для реализации строгого фильтра можно заменить выражение в функции MatchAttrs простым равенством: flags = attrs.

Возможный результат поиска с использованием функции SearchInFolder показан на рис. 4.5.

Рис. 4.5. Поиск в заданной папке


Пример кода вызова функции SearchlnFolder (для показанного на рис. 4.5 приложения) приведен в листинге 4.25.

Листинг 4.25. Использование функции SearchlnFolder

//Запуск поиска файла в заданной папке

procedure TForm2.Button1Click(Sender: TObject);

var

flags: DWORD;

begin

//Формируем набор атрибутов (по установленным флажкам на форме)

flags:= 0;

if (chkDirs.Checked) then flags:= flags or FILE_ATTRIBUTE_DIRECTORY;

if (chkHidden.Checked) then flags:= flags or FILE_ATTRIBUTE_HIDDEN;

if (chkSystem.Checked) then flags:= flags or FILE_ATTRIBUTE_SYSTEM;

if (chkReadOnly.Checked) then flags:= flags or FILE_ATTRIBUTE_READONLY;

if (chkArchive.Checked) then flags:= flags or FILE_ATTRIBUTE_ARCHIVE;

lblFound.Caption:= 'Поиск...';

lstFiles.Clear;

Refresh;

//Поиск (файлы записываются прямо в список на форме)

if not SearchInFolder(txtFolder.Text, txtMask.Text, flags,

lstFiles.Items)

then

lblFound.Caption:= 'Поиск не дал результатов'

else

lblFound.Caption:= ' Найдено объектов: '+ IntToStr(lstFiles.Count);

end;


Поиск по всему дереву папок

В листинге 4.26 приведена одна из возможных реализаций рекурсивного поиска по дереву папок. Алгоритм поиска следующий.

1. Выполняется поиск в папке folder (все найденные файлы или папки добавляются в список names).

2. Функция SearchlnTree вызывается для каждой подпапки папки folder для продолжения поиска в поддереве, определяемом каждой подпапкой.

Листинг 4.26. Поиск по дереву папок

function SearchInTree(folder, mask: String; flags: DWORD;

names: TStrings; addpath: Boolean = False): Boolean;

var

hSearch: THandle;

FindData: WIN32_FIND_DATA;

bRes: Boolean; //Если равен True, то найден хотя бы один файл или папка

begin

//Осуществляем пои ск в текущей папке

bRes:= SearchInFolder(folder, mask, flags, names, addpath);

//Продолжим поиск в каждой из подпапок

hSearch:= FindFirstFile(PAnsiChar(folder + '*'), FindData);

if (hSearch <> INVALID_HANDLE_VALUE) then

begin

repeat

if (String(FindData.cFileName) <> '..') and

(String(FindData.cFileName) <> '.') then //Пропускаем . и ..

begin

if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY <> 0)

then

//На йдена подпапка – выполним в ней поиск

if SearchInTree(folder + ''+ String(FindData.cFileName),

mask, flags, names, addpath)

then

bRes:= True;

end;

until FindNextFile(hSearch, FindData) = False;

FindClose(hSearch);

end;

SearchInTree:= bRes;

end;


В функции SearchInTree используется просмотр папки folder вручную (с помощью API-функций) из соображений эффективности. Если захотите, можете реализовать поиск подпапок с помощью функции SearchlnFolder. Правда, для этого придется завести дополнительный список (TStringList) для сохранения найденных в текущей папке подпапок. Элементы списка будут использоваться только один раз: для поиска в подпапках.

Возможный результат поиска с использованием функции SearchInTree приводится на рис. 4.6.

Рис. 4.6. Поиск по дереву папок


С небольшими изменениями алгоритм рекурсивного обхода дерева папок, реализованный в листинге 4.25, можно использовать и при операциях, отличных от простого поиска: например, при копировании или удалении дерева папок. Для этого достаточно выполнять нужные операции над каждым находимым объектом.


Страницы книги >> Предыдущая | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | Следующая
  • 0 Оценок: 0

Правообладателям!

Это произведение, предположительно, находится в статусе 'public domain'. Если это не так и размещение материала нарушает чьи-либо права, то сообщите нам об этом.


Популярные книги за неделю


Рекомендации