Каталог расширений

Популярные теги

3gp       avi       fb2       jpg       mp3       pdf      

Как проверить наличие файла в делфи


Как проверить существование файла на Delphi

Проверяем – существует ли файл на Delphi

Нам поможет функция FileExists. Она проверяет наличие искомого файла, и функция возвращает – True, если он существует и False – если он отсутствует.

В качестве примера, возьмём какой-либо файл и запомним адрес директории его предполагаемого размещения. Допустим, возьмём один из своих аудио файлов – Мелодия.wav и скопируем его на диск C:/

Далее:

1) Кидаем на форму компонент Button1 и в событии OnClick прописываем следующее:

begin

if FileExists(AnsiString('C:/Мелодия.wav')) then

//AnsiString - позволяет содержать последовательность

//символов, подобно предложениям...

begin

ShowMessage('Файл существует');

end

else

begin

ShowMessage('Файл отсутствует');

end;

2) Запускаем приложение, нажимаем на кнопку и видим появившееся сообщение – “Файл существует”, а если мы, наш файл переместим куда нибудь в другое место, и снова нажмем на Button, то увидим сообщение –  “Файл отсутствует”.


Вконтакте

Facebook

Twitter

Google+

Одноклассники

Мой мир

E-mail

Delphi.WinAPI. Доступен ли файл для чтения?

function CheckFileAccess(const FileName: string; const CheckedAccess: Cardinal): Cardinal;

 

var

  Token: THandle;

  Status: LongBool;

  Access: Cardinal;

  SecDescSize: Cardinal;

  PrivSetSize: Cardinal;

  PrivSet: PRIVILEGE_SET;

  Mapping: GENERIC_MAPPING;

  SecDesc: PSECURITY_DESCRIPTOR;

begin

  Result := 0;

 

  GetFileSecurity

  (

  PChar(Filename),

  OWNER_SECURITY_INFORMATION or GROUP_SECURITY_INFORMATION or DACL_SECURITY_INFORMATION,

  nil,

  0,

  SecDescSize

  );

 

  SecDesc := GetMemory(SecDescSize);

 

  if GetFileSecurity

  (

  PChar(Filename),

  OWNER_SECURITY_INFORMATION or GROUP_SECURITY_INFORMATION or DACL_SECURITY_INFORMATION,

  SecDesc,

  SecDescSize,

  SecDescSize

  ) then

 

  begin

    ImpersonateSelf(SecurityImpersonation);

    OpenThreadToken(GetCurrentThread, TOKEN_QUERY, False, Token);

    if Token <> 0 then

    begin

      Mapping.GenericRead := FILE_GENERIC_READ;

      Mapping.GenericWrite := FILE_GENERIC_WRITE;

      Mapping.GenericExecute := FILE_GENERIC_EXECUTE;

      Mapping.GenericAll := FILE_ALL_ACCESS;

      MapGenericMask(Access, Mapping);

      PrivSetSize := SizeOf(PrivSet);

      AccessCheck(SecDesc, Token, CheckedAccess, Mapping, PrivSet, PrivSetSize, Access, Status);

      CloseHandle(Token);

      if Status then

        Result := Access;

    end;

  end;

  FreeMem(SecDesc, SecDescSize);

end;

Delphi проверка существования файла

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

Проверка, существует ли файл или папка:

В процессе разработки очень часто возникает потребность в том, чтобы проверить существует ли файл или папка. В Delphi предусмотрены специальные функции для проверки:

function FileExists ( const FileName : string) : Boolean; — проверяет существует ли файл. В функцию нужно передать имя файла с полным путем к нему. Например, такое ‘c:/1.html’. На выходе получаем булевское значение (истина/ложь).

function DirectoryExists(const Directory: string): Boolean; — принцип работы напоминает принцип предыдущей функции. Только передавать нужно путь к папке. В ответ получаем все те же истину или ложь.

Пример использования:

FileExist может пригодиться, если Вы в программе пытаетесь создать файл, но Вам нужно убедиться, что файла с таким названием нет. Пример с использованием данной функции тут. DirectoryExists тоже может быть очень полезна. Приведу пример. Вам нужно сохранить файл каком-либо каталоге. Если такого каталога не окажется, то файл не сохранится и произойдет ошибка. Так что перед тем как сохранить файл, если Вы не уверены в существовании директории, лучше проверить.

Если Вам нужен пример того, как использовать DirectoryExists — напишите мне в комментариях к статье. Я обязательно придумаю пример и опишу его отдельной статье. В принципе я готов ответить на любые интересующие вопросы — задавайте.

В этой статье мы узнаем как проверить существование файла.
В FormCreate или Button1Click пишем код проверки файла на существование:

Вот и всё, Удачи!

Источник: www.thedelphi.ru
Автор: Савельев Александр
Опубликовано: 5 Апреля 2012
Просмотров: 10953

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

Функция FileExists() выполняет проверку на наличие файла в заданной директории.

Если указанный параметром файл существует, возвращает значение True. Если файл не обнаружен, функция возвращает значение False.

function FileExists( const FileName: string): Boolean;

классика Pascal. Работа с типизированными файлами в Delphi

Удивительно, но факт – запрос “delphi файлы” в Яндексе – это один из самых популярных запросов, касающихся Delphi. Популярнее только “delphi скачать” – видимо ещё не все слышали про такую штуку как Delphi Community Edition. Раз есть в Сети запрос – должен быть и ответ. Посмотрим, что получится в итоге.

Содержание статьи

Классика работы с файлами в Delphi – ключевое слово File

Этот способ, без преувеличения, можно назвать древнейшим способом работы с файлами в Pascal/Delphi. Однако и он до сих пор используется в работе, особенно, если это, например, лабораторная работа по информатике в школе или ВУЗе.

Для определения файловой переменной в Delphi/Pascal используется ключевое слово File. При этом, мы можем определить как типизированный файл, так и не типизированный, например:

type TPerson = record Name: string[20]; Family: string[20]; end;   var UntypedFile: File; //нетипизированный двоичный файл TypedFile: File of TPerson;//типизированный файл

Для типизированного фала мы можем задать тип данных фиксированного размера (ShortString, String[20], Integer, Single и так далее), например, мы можем определить такие типизированные файлы:

 IntFile: File of integer; StringFile: file of single; ShortStringFile: file of ShortString;

Или, как в примере выше использовать для указания типа запись (record), в которой все поля имеют фиксированный размер. Для типизированного файла нельзя указывать типы данных, размер которых не фиксирован, например, вот такие определения файловых переменных недопустимы:

type TIntArr = array of integer;   var StrFile: file of string; //недопустимо - размер string заранее не известен ArrFile: file of TIntArr;//недопустимо - размер динамического массива заранее неизвестен

Более того, даже компилятор Delphi укажет вам на ошибку, сообщив следующее:

[dcc32 Error] E2155 Type ‘string’ needs finalization – not allowed in file type

Определив файловую переменную можно приступать к работе с файлом. Алгоритм работы при этом будет следующим:

  1. Ассоциировать файловую переменную с файлом на диске
  2. Открыть файл
  3. Записать/Прочитать файл
  4. Закрыть файл

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

Работа с типизированными файлами в Delphi

Рассмотрим несколько примеров работы с типизированными файлами в Delphi.
Для начала, рассмотрим вариант работы с типизированным файлом, например, представленном выше:

type TPerson = record Name: string[20]; Family: string[20]; end; var TypedFile: File of TPerson;

Пример №1. Запись данных в типизированный файл Delphi

Запишем в наш файл две записи:

program example_1;   {$APPTYPE CONSOLE}   {$R *.res}   uses System.SysUtils;   type TPerson = record Name: string[20]; Family: string[20]; end;   var TypedFile: File of TPerson; Person: TPerson; begin //связываем файловую переменную с файлом на диске AssignFile(TypedFile,'MyFile.txt'); //открываем файл для записи Rewrite(TypedFile); //задаем имя/фамилию человека Person.Name:='Иван'; Person.Family:='Иванов'; //добавляем запись в файл Write(TypedFile, Person); //задаем имя/фамилию второго человека Person.Name:='Петр'; Person.Family:='Петров'; //записываем в файл Write(TypedFile, Person); //закрываем файл CloseFile(TypedFile);   Readln; end.

Рассмотрим методы, используемые в этом примере:

function AssignFile(var F: File; FileName: String): Integer;

Связывает файловую переменную F с внешним файлом FileName. В качестве второго параметра может задаваться как абсолютный путь к файлу, например, ‘C:/MyFile.txt‘, так и относительный, например, в коде выше файл будет создан рядом с exe-файлом.

procedure Rewrite(var F: File; [ RecSize: Integer]);

Создает новый файл и открывает его. Если внешний файл с таким именем уже существует, он удаляется и на его месте создается новый пустой файл. Если F уже открыт, он сначала закрывается, а затем воссоздается. Текущая позиция файла устанавливается в начале пустого файла.
F – это переменная, связанная с внешним файлом с использованием AssignFile. RecSize – это необязательное выражение, которое можно указывать, только если F является нетипизированным файлом (об этом ниже).

procedure Write([var F: File]; P1; [ ..., PN]); overload;

Используется для записи в типизированный файл. F – файловая переменная, P1..PN – это переменная того же типа, что и тип файла F.

procedure CloseFile(var F: File);

Прекращает связь между файловой переменной и файлом внешнего диска. F – это файловая переменная любого типа. Внешний файл, связанный с F, полностью обновляется, а затем закрывается, освобождая дескриптор файла для повторного использования.

В результате выполнения представленного выше кода, рядом с exe-файлом будет создан новый файл MyFile.txt, содержащий две записи, при этом, каждая запись будет иметь фиксированный размер, вне зависимости от фактических имени/фамилии.

Для того, чтобы в delphi не перезаписывать каждый раз файл, а добавлять в конец файла новые записи необходимо открывать типизированные файлы методом Reset. Рассмотрим пример добавления новых записей в типизированные файлы Delphi.

Пример №2. Добавление записей в типизированный файл Delphi

Рассмотрим такой пример Delphi:

program example_2;   {$APPTYPE CONSOLE}   {$R *.res}     uses System.SysUtils;   type TPerson = record Name: string[20]; Family: string[20]; Age: integer; end;   procedure ReadTypedFile; const cStr = '%s %s %d'; var F: File of TPerson; Person: TPerson; begin AssignFile(F, 'MyFile.txt'); Reset(F); while not Eof(F) do begin Read(F, Person); Writeln(Format(cStr, [Person.Name, Person.Family, Person.Age])); end; end;   procedure AppendTypedFile; var F: file of TPerson; Person: TPerson; begin AssignFile(F, 'MyFile.txt'); // открываем файл для записи Reset(F); Seek(F, FileSize(F)); // задаем имя/фамилию человека Writeln('Введите имя: '); Readln(Person.Name); Writeln('Введите фамилию: '); Readln(Person.Family); Writeln('Введите возраст: '); Readln(Person.Age); // добавляем запись в файл Write(F, Person); // закрываем файл CloseFile(F); end;   var TypedFile: File of TPerson; Person: TPerson; DoAppend: integer;   begin if not FileExists('MyFile.txt') then begin AssignFile(TypedFile, 'MyFile.txt'); // открываем файл для записи Rewrite(TypedFile); // закрываем файл CloseFile(TypedFile); end;   // связываем файловую переменную с файлом на диске repeat Writeln('Добавить в файл запись: 1 - Да; 2 - Нет'); Readln(DoAppend); case DoAppend of 1: AppendTypedFile; 2: break; end; until DoAppend = 0; //читаем все записи из типизированного файла ReadTypedFile; Readln; end.

Разберемся с тем, что здесь делается. Во-первых, условие:

if not FileExists('MyFile.txt') then

проверяет, существует ли файл на диске. Метод FileExist имеет следующее описание:

function FileExists(const FileName: string; FollowLink: Boolean = True): Boolean;

FileName – имя файла, существование которого необходимо проверить. Второй параметр – FollowLink учитывается только при использовании символической ссылки. То есть, если нужно проверить только наличие символической ссылки на файл, то параметр FollowLink устанавливается в False, а если нужно проверить наличие и символической ссылки на файл и самого файла, то FollowLink устанавливается в True (значение по умолчанию).

Таким образом, в нашем примере, если файла нет на диске то он создается пустым. Далее выполняется цикл:

repeat Writeln('Добавить в файл запись: 1 - Да; 2 - Нет'); Readln(DoAppend); case DoAppend of 1: AppendTypedFile; 2: break; end; until DoAppend = 0;

В этом цикле, если пользователь вводит 1, выполняется процедура AppendTypedFile, которая добавляет в файл очередную запись:

procedure AppendTypedFile; var F: file of TPerson; Person: TPerson; begin AssignFile(F, 'MyFile.txt'); // открываем файл для записи Reset(F); //смещаемся в конец файла Seek(F, FileSize(F)); // задаем имя/фамилию человека Writeln('Введите имя: '); Readln(Person.Name); Writeln('Введите фамилию: '); Readln(Person.Family); Writeln('Введите возраст: '); Readln(Person.Age); // добавляем запись в файл Write(F, Person); // закрываем файл CloseFile(F); end;

Здесь, в принципе, весь алгоритм расписан в комментариях к процедуре.
Метод Reset не воссоздает файл снова, как Rewrite, а открывает его для чтения/записи (в случае двоичных файлов). Что касается метода Seek, то он имеет следующее описание:

procedure Seek(var F: File; N: Integer);

F – файловая переменная, ассоциированная с файлом на диске, N – номер записи в файле (первый номер – 0). Чтобы переместиться сразу в конец файла, мы сделали такой вызов:

где FileSize – это метод Delphi имеющий следующее описание:

function FileSize(var F: File): Integer;

В случае использования типизированных файлов эта функция возвращает количество записей в файле.

После того, как пользователь вводит что-то кроме 1 срабатывает метод ReadTypedFile – чтение всех записей из файла:

procedure ReadTypedFile; const cStr = '%s %s %d'; var F: File of TPerson; Person: TPerson; begin AssignFile(F, 'MyFile.txt'); Reset(F); while not Eof(F) do begin Read(F, Person); Writeln(Format(cStr, [Person.Name, Person.Family, Person.Age])); end; end;

Здесь мы, опять же, открываем файл методом Reset и в цикле while..do проходим по всем записям файла, пока не дойдем до конца. Здесь мы использовали два новых метода Delphi:

function Eof([var F: File]): Boolean; overload;

Eof возвращает True, если текущая позиция файла находится за последним символом файла или файл пуст. В противном случае Eof возвращает False.
По аналогии с методом Write, метод Read производит чтение очередной записи из файла и имеет следующее описание:

procedure Read(var F: File; V1; [ ..., VN]);

Результат работы нашего примера может быть следующим:

Ещё одним полезным методом для работы с типизированными файлами может быть процедура Truncate:

procedure Truncate(var F: File);

Удаляет все записи после текущей позиции файла. Вызовите Truncate в коде Delphi, чтобы текущая позиция файла стала концом файла (Eof (F) вернет true).
Рассмотрим пример использования этой процедуры.

Пример №3. Удаление последних записей типизированного файла в Delphi

Воспользуемся файлом, созданным в предыдущем примере и удалим из него две последние записи:

program example_3;   {$APPTYPE CONSOLE}   {$R *.res}     uses System.SysUtils;   type TPerson = record Name: string[20]; Family: string[20]; Age: integer; end;   procedure ReadTypedFile; const cStr = '%s %s %d'; var F: File of TPerson; Person: TPerson; begin AssignFile(F, 'MyFile.txt'); Reset(F); while not Eof(F) do begin Read(F, Person); Writeln(Format(cStr, [Person.Name, Person.Family, Person.Age])); end; end;   var TypedFile: File of TPerson; Person: TPerson; Count: integer; DoErase: integer; begin AssignFile(TypedFile,'MyFile.txt'); Reset(TypedFile); Count:=FileSize(TypedFile); if Count&lt;2 then begin Writeln('Количество записей в файле меньше двух. Стереть все записи? 1 - Да; 2 - Нет'); Readln(DoErase); if DoErase=1 then Truncate(TypedFile); end else begin Seek(TypedFile, Count-2); Truncate(TypedFile); end; //читаем все записи из типизированного файла ReadTypedFile; Readln; end.

В этом примере мы делаем следующее:

  1. Открываем файл существующий AssignFile/Reset
  2. Определяем количество записей в файле (Count:=FileSize(TypedFile))
  3. Если количество записей меньше двух, то спрашиваем у пользователя стереть ли все записи и, в случае положительного ответа, вызываем метод Tuncate
  4. Если количество записей в файле больше двух, то смещаемся на нужную нам позицию в файле (Seek(TypedFile, Count-2)) и затираем две последние записи методом Truncate.

Подведем итог

Для работы с типизированными файлами в Delphi в самом общем случае нам необходимо выполнить следующую последовательность операций:

  1. Определить тип записей в файле – это могут быть стандартные типы данных Delphi с фиксированным размером: ShortString, integer, single и так далее или собственные типы данных, например, записи (record), но, в этом случае, главное условие – размер записи должен быть фиксированным.
  2. В коде Delphi/Pascal определить файловую переменную, используя ключевое слово file и, указав тип записей файла, определенный в пункте 1.
  3. Ассоциировать файловую переменную с внешним файлом на диске, используя метод AssignFile.
  4. Открыть файл для чтения/записи, используя методы Rewrite/Reset.
  5. Чтобы сделать в файл очередную запись используем метод Write, для чтения очередной записи из файла – используем метод Read.
  6. Закрыть файл методом CloseFile.

В целом, рассмотренные выше примеры не охватывают всех возможностей работы с типизированными файлами в Delphi, а, скорее, показывают основные операции по работе с типизированными файлами. Поэтому ниже представлен перечень методов которые могут применяться при работе с типизированными файлами в Delphi/Pascal.

Функции и процедуры для работы с типизированными файлами в Delphi/Pascal

Метод Краткое описание
procedure AssignFile(var F: File; FileName: String)
Ассоциирует файловую переменную F с внешним файлом FileName. Переменная FileName может быть как именем файла, так и содержать полный путь к файлу на диске.
procedure CloseFile(var F: File);
Закрывает файл, ассоциированный с переменной F и освобождает переменную для дальнейшего использования.
function Eof(var F: File): Boolean;
Проверяет конец файла и возвращает True, если файловый указатель стоит в конце файла. В случае записи True означает, что очередной компонент будет добавлен в конец файла, при чтении – что файл прочтен полностью.
procedure Erase(var F: File);
Удаляет внешний файл, связанный с файловой переменной F. Перед удалением файла его необходимо закрыть методом CloseFile.
 
function FilePos(var F: File): Integer;
Возвращает текущую позицию в файле. В коде Delphi используйте FilePos для файловой переменной открытого файла, чтобы определить текущую позицию в файле. Если текущая позиция в файле находится в начале, FilePos возвращает 0.
 
function FileSize(var F: File): Integer;

 

Для типизированных файлов возвращает количество записей в файле.
procedure Read(var F: File; V1; [ ..., VN]);
Считывает из типизированного файла одну или несколько записей
procedure Rename(var F: File; Newname: String);
Переименовывает файл, ассоциированный с переменной F
procedure Reset(var F: File; [ RecSize: Integer]);
Открывает файл для чтения. Второй параметр RecSize указывается в случае использования нетипизированных файлов и указывает размер записи в файле в байтах
procedure Rewrite(var F: File; [ RecSize: Integer]);
Воссоздает файл. Если файл существует, то Rewrite его удалит, а затем создаст снова. RecSize используется для нетипизированных файлов
procedure Seek(var F: File; N: Integer);
Перемещает текущую позицию в файле к записи N (первая запись имеет номер 0)
procedure Truncate(var F: File);
Стирает из файла данные, расположенные за текущей позицией
procedure Write([var F: File]; P1; [ ..., PN]);
Записывает в файл F одну или несколько записей
Take Our Poll

0 0 голос

Рейтинг статьи

работа с директориями в Delphi 2010.

С выходом версии 2010 в Delphi появился ещё один модуль – IOUtils.pas облегчающий работу с файлами и директориями. Признаться я просто катострофически не люблю работу с файлами в Delphi. Незнаю почему, но всегда напрягало реализовывать поиск по маске, чтение атрибутов и т.д. и т.п. Может из-за этого и решил рассмотреть, что же такого нового и облегчающего мою жизнь приготовили разработчики из Embarcadero.

Вначале обратимся к официальной Wiki Embarcadero и посмотрим, что там пишут про IOUtils:

…IOUtils contains three static classes: TDirectory, TPath and TFile. These classes expose a number of static methods useful for I/O tasks. …

Отлично. Всего три класса, содержащие ряд классовых методов. Начнем по порядку – с TDirectory.

TDirectory – работа с директориями.

Вспомним навскидку, какие операции с директориями обычно приходится выполнять. Мне вспомнились следующие операции:
1. Проверить существование директории;
2. Проверить наличие файлов в директории;
3. Перечислить все файлы в директории;
4. Перечислить вложенные директории;
5. Проверить даты создания/изменения директории;
6. Перечислить все логические диски в системе.
В целом, все эти операции уже давным давно расписаны на форумах, всяческих FAQ по Delphi и т.д. Так что, если потребуется найти “классический” вариант выполнения операции – Google в помощь. А мы посмотрим как можно реализовать всё это с помощью IOUtils.pas.

Как проверить существование директории, создать, удалить или скопировать директорию?

Используя IOUtils.pas проверить существование директории можно следующим образом:

if TDirectory.Exists('full_path_to_dir') then ShowMessage('Directory Exists') else ShowMessage('Directory Not Found');

Соответственно, если директория отсутствует, то её можно создать:

TDirectory.CreateDirectory('path_to_dir');

А если директория существует, то её можно скопировать в другое место:

TDirectory.Copy('source_path','dest_path');

При этом копируется всё содержимое директории. И наконец удалить ненужную директорию:

TDirectory.Delete('path_to_dir');

Как проверить наличие файлов в директории? Как построить дерево каталогов? Поиск по маске. Использование TSearchRec.

Если необходимо получить только факт – есть или нет что-либо в директории, что можно воспользоваться следующим методом:

if TDirectory.IsEmpty(Edit1.Text) then ShowMessage('Directory Empty') else ShowMessage('Directory Not Empty');

При этом, если даже в директории содержится ещё одна пустая папка, то IsEmpty вернет False.
Если нам необходимо перечислить все поддиректории, то здесь в нашем распоряжении сразу несколько вариантов:
1. Простое перичисление всех директорий:

var Dirs: TStringDynArray; ... Dirs:=TDirectory.GetDirectories('path'); ...

Здесь TStringDynArray – динамический массив (array of string). Тип TStringDynArray определен в модуле Types.
2. Поиск директорий по маске
Если простого перечисления недостаточно и необходимо найти только определенные директории, то можно воспользоваться методом GetDirectories, используя маску. В следующем примере в массив попадут все поддиректории, содержищие в названии “ee”:

 Drives:=TDirectory.GetDirectories(Edit1.Text,'*ee*');

2. Поиск директорий по уровням
По умолчанию GetDirectories проводит поиск директорий только первого уровня. Как быть, если нам необходимо пройтись по всем вложенным папкам? С появлением IOUtils в Delphi все стало проще. Достаточно использовать опции поиска:

TSearchOption = (soTopDirectoryOnly, soAllDirectories);

Соответсвенно, включив soAllDirectories в GetDirectories мы получим полное дерево каталогов:

Drives:=TDirectory.GetDirectories('path_to_dir','*',TSearchOption(1));

А как быть, если по-мимо простого поиска нам необходимо как-то визуализировать процесс или, например, в процессе поиска учитывать атрибуты директории?
3. Поиск с использованием TFilterPredicate
В этом случае можно воспользоваться процедурной ссылкой:

type TFilterPredicate = reference to function(const Path: string; const SearchRec: TSearchRec): Boolean;

Как видите, в параметрах используется уже давно нам изветный тип TSearchRec, которым мы привыкли пользоваться при поиске файлов/директорий:

TSearchRec = record Time: Integer; Size: Int64; Attr: Integer; Name: TFileName; ExcludeAttr: Integer; {$IFDEF MSWINDOWS} FindHandle: THandle platform; FindData: TWin32FindData platform; {$ENDIF MSWINDOWS} {$IFDEF POSIX} Mode: mode_t platform; FindHandle: Pointer platform; PathOnly: String platform; Pattern: String platform; {$ENDIF POSIX} end;

Посмотрим простой пример поиска директорий с использованием TFilterPredicate. В следующем коде в результат поиска будут включены только те директории, которые будут содержить в названии подстроку ‘api’, поиск будет проводится по всему дереву каталогов:

... function FilterPredicate(const Path: string; const SearchRec: TSearchRec):boolean; begin Result:=pos('api',SearchRec.Name)&gt;0 end; ... Drives:=TDirectory.GetDirectories(Edit1.Text,'*',TSearchOption(1),FilterPredicate);

Так как при использовании TFilterPredicate в нашем распоряжении имеется достаточное количество информации по текущему результату поиска, то помимо простого фильтра поиска, мы можем также подсчитать в процессе поиска размер всех файлов, запомнить какие-либо результаты и т.д. и т.п.
Всего TDirectory содержит шесть переопределенных методов GetDirectories:

class function GetDirectories(const Path: string): TStringDynArray; overload; inline; static; class function GetDirectories(const Path: string; const Predicate: TFilterPredicate): TStringDynArray; overload; inline; static; class function GetDirectories(const Path, SearchPattern: string): TStringDynArray; overload; inline; static; class function GetDirectories(const Path, SearchPattern: string; const Predicate: TFilterPredicate): TStringDynArray; overload; inline; static; class function GetDirectories(const Path, SearchPattern: string; const SearchOption: TSearchOption): TStringDynArray; overload; static; class function GetDirectories(const Path, SearchPattern: string; const SearchOption: TSearchOption; const Predicate: TFilterPredicate): TStringDynArray; overload; static; class function GetDirectories(const Path: string; const SearchOption: TSearchOption; const Predicate: TFilterPredicate): TStringDynArray; overload; static;

Так что, для поиска и перечисления директорий возможностей у нас более, чем досаточно. Аналогичным образом проводится и поиск всех файлов в директории. Поиск файлов проводится с использованием одной из семи классовых функций GetFiles – параметры методов абсолютно идентичны тем, что используются в GetDirectories.

Как получить даты создания, последнего доступа и записи в директорию?

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

var Date:TDateTime; Date:=TDirectory.GetCreationTime('path');//дата создания Date:=TDirectory.GetLastAccessTime('path');//дата последнего доступа Date:=TDirectory.GetLastWriteTime('path');//дата последнего изменения

Как перечислить все логические диски в системе?

Получить все логические диски теперь можно, выполнив всего лишь одну классовую функцию:

var Drives: TStringDynArray; ... Drives:=TDirectory.GetLogicalDrive

В результате чего мы получим массив, содержащий все логические диски в системе.
И, наконец, ещё три метода, которые могут пригодится нам при работе с директориями:

TDirectory.GetCurrentDirectory

Возвращает текущую директорию. Можно использовать, например, аналог

ExtractFilePath(Application.ExeName)

GetCurrentDirectory возвращает полный путь к директории без последнего ‘\’.
Второй метод:

TDirectory.GetDirectoryRoot('path')

Возвращает корень для директории, т.е. по сути, логический диск на котором располагается директория. Если надо получить родительскую директорию, то используется третий метод:

TDirectory.GetParent('path')

Вот пожалуй в нескольких словах обзор методов TDirectory. В целом можно сказать, что IOUtils.pas может достаточно облегчить нашу работу в плане выполнения каких-то, ставших уже рутинных для нас, операций. Например, обход дерева каталогов, поиск файлов и директорий по маске и т.д. В следующей части посмотрим, что можно сделать с помощью методов TFile.

0 0 голос

Рейтинг статьи

Мониторинг изменений в директориях и файлах средствами Delphi. Часть #1.

При разработке приложений Delphi для синхронизации чего-либо, например, файлов на разных компьютерах, так или иначе приходится разрабатывать алгоритм с помощью которого можно однозначно определять какие из файлов необходимо удалить из определенной директории, какие переместить, переименовать и т.д. Подобные алгоритмы и примеры их использования на практике не являются редкостью – в Сети Вы можете найти массу самых различных вариаций Delphi-кода с помощью которого можно отследить изменения в директориях и файлах Windows.

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

Самым простым и легкодоступным даже для новичков в программировании способом слежения за изменениями в директории является работа по таймеру. Смысл работы заключается в том, что на старте работы программы создается список файлов и поддиректорий в целевой директории. Затем, в момент срабатывания таймера, создается новый список и сравнивается с предыдущим – определяется какие файлы были добавлены, какие удалены/перемещены и т.д. и по уже определенным изменениям проводятся операции синхронизации.  Как в данном случае определить, что, скажем, файл Test.txt был изменен? Например, можно рассчитывать каждый раз CRC файла и сравнивать эту сумму с предыдущим значением. Вот исходник функции с  www.delphisources.ru, для расчёта CRC файла:

function GetCheckSum(FileName: string): DWORD; var F: file of DWORD; P: Pointer; Fsize: DWORD; Buffer: array[0..500] of DWORD; begin FileMode := 0; AssignFile(F, FileName); Reset(F); Seek(F, FileSize(F) div 2); Fsize := FileSize(F) - 1 - FilePos(F); if Fsize &gt; 500 then Fsize := 500; BlockRead(F, Buffer, Fsize); Close(F); P := @Buffer; asm xor eax, eax xor ecx, ecx mov edi , p @again: add eax, [edi + 4*ecx] inc ecx cmp ecx, fsize jl @again mov @result, eax end; end;

Пример использования функции. Создадим новое приложение в Delphi со следующими компонентами на форме:

При открытии файла будем определять его размер и рассчитывать CRC с помощью приведенной выше функции:

uses IOUtils; [...] procedure TForm3.Button1Click(Sender: TObject); begin if OpenDialog1.Execute then begin edFile.Text:=OpenDialog1.FileName; lbCRC.Caption:=IntToStr(GetCheckSum(OpenDialog1.FileName)); lbSize.Caption:=IntToStr(TFile.OpenRead(OpenDialog1.FileName).Size); end; end;

Теперь возьмем создадим текстовый файлик и запишем в него строку, скажем “Hello World!”, сохраним его, запустим программу и рассчитаем CRC. Вот, что получилось в программе:

Теперь снова откроем файл и заменим заглавные буквы на прописные, т.е. строка примет вид “hello world!”. Снова рассчитаем CRC:

Обратите внимание, что размер файла остался прежним, а содержимое файла изменилось. Это лишний пример того, что использование в качестве критерия изменения файла только его размера – это очень ненадежный вариант и, наверное, даже неправильный.

Что можно сказать по поводу предложенного выше варианта мониторинга изменения в директории с помощью таймера?

Достоинством этого метода можно назвать его простота. Не важно, какой таймер будет использоваться в работе – стандартный TTimer или собственноручно созданный высокоточный таймер. Повесить обработчик на срабатывание таймера сможет кто угодно. Но наряду с простотой этого варианта он также имеет и массу недостатков. И самый главный из недостатков – ненадежность.

Никто не даст Вам гарантий того, что заданный интервал срабатывания таймера будет достаточным для выполнения процедуры обработчика. Как говориться, компьютер пользователя – потёмки. Можно, конечно, задавать большой интервал времени и надеяться на то, что обработчик таймера отработает на 100%, но это всего-лишь “костыль”, но никак не решение проблем надежности алгоритма.

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

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

  1. Мониторинг изменений в директории без вывода информации об изменениях, т.е. простая констатация факта – было изменение, а что именно было изменено не определяется. Для этого способа используется тройка функций: FindFirstChangeNotification, FindNextChangeNotification, FindCloseChangeNotification.
  2. Мониторинг изменений в директории с выводом информации по измененным элементам. Для этого способа используется пара функций: CreateFile и ReadDirectoryChangesW.

Оба этих способа в равной степени удобны, но какой из этих способов использовать в конкретной ситуации решать только Вам. Рассмотрим примеры использования функций Windows для мониторинга изменений в директориях.

Использование функций FindFirstChangeNotification, FindNextChangeNotification, FindCloseChangeNotification

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

unit Monitor;   interface   uses Classes, Windows, SysUtils;   type TChangeMonitor = class(TThread) private public protected procedure Execute; override; end;   implementation   { TChangeMonitor }   procedure TChangeMonitor.Execute; begin {здесь будем проводить мониторинг} end;   end.

Теперь рассмотрим назначение функций Windows.

FindFirstChangeNotification – создает дескриптор уведомления об изменениях и устанавливает начальные условия отправки уведомления. Функция возвращает дескриптор (THandle) либо INVALID_HANDLE_VALUE в случае ошибки:

FindFirstChangeNotification(lpPathName: PChar; bWatchSubtree: boolean; dwNotifyFilter:DWORD): THandle;

lpPathName: PChar – полный путь к директории за которой проводится слежение. Значение этого параметра не может содержать относительный путь или пустую строку.
bWatchSubtree: booleanTrue – указывает на то, что также в результат мониторинга будут попадать изменения в поддиректориях.
dwNotifyFilter:DWORD – набор флагов, определяющих настройки фильтра. Флаги могут быть следующими:

  • FILE_NOTIFY_CHANGE_FILE_NAME (0x00000001) – любое изменение имени файла в каталоге или подкаталоге.  Изменения включают в себя переименование, создание или удаление файла.
  • FILE_NOTIFY_CHANGE_DIR_NAME (0x00000002) – любое изменение имени директории в каталоге или подкаталоге.  Изменения включают в себя переименование, создание или удаление директории.
  • FILE_NOTIFY_CHANGE_ATTRIBUTES (0x00000004) – любое изменение атрибутов в просматриваемой директории и поддиректориях.
  • FILE_NOTIFY_CHANGE_SIZE (0x00000008) – изменение размера файла в директории или поддиректории. Изменение размера обнаруживается только когда файл записывается на диск.
  • FILE_NOTIFY_CHANGE_LAST_WRITE (0x00000010) – изменение времени последней записи в файл.
  • FILE_NOTIFY_CHANGE_SECURITY (0x00000100) – изменение параметров безопасности в каталоге или подкаталоге.

 

FindNextChangeNotification – указывает, чтобы операционная система вернула сигнал уведомления об изменении THandle в следующий раз, когда обнаруживаются изменения, согласно фильтру, установленному функцией FindFirstChangeNotification.

FindNextChangeNotification(hChangeHandle: THandle):boolean;

hChangeHandle: THandle – дескриптор, полученный с помощью функции FindFirstChangeNotification.

FindCloseChangeNotification – останавливает мониторинг изменений в директории.

FindCloseChangeNotification(hChangeHandle: THandle):boolean;

hChangeHandle: THandle – дескриптор, полученный с помощью функции FindFirstChangeNotification.

Назначение функций теперь более или менее стали нам понятны – осталось закрепить полученные знания на опыте. Итак, прежде всего наш поток должен получать два значения: путь к директории за которой мы будем следить и флаг, указывающий следует ли мониторить подкаталоги. Пишем конструктор потока:

type TChangeMonitor = class(TThread) private FDirectory: string; FScanSubDirs: boolean; public constructor Create(ASuspended: boolean; ADirectory:string; AScanSubDirs: boolean); protected procedure Execute; override; end;   implementation   { TChangeMonitor }   constructor TChangeMonitor.Create(ASuspended: boolean; ADirectory: string; AScanSubDirs: boolean); begin inherited Create(ASuspended); FDirectory:=ADirectory; FScanSubDirs:=AScanSubDirs; FreeOnTerminate:=true; end;

Теперь создадим следующий Execute:

procedure TChangeMonitor.Execute; var ChangeHandle: THandle; begin {получаем хэндл события} ChangeHandle:=FindFirstChangeNotification(PChar(FDirectory), FScanSubDirs, FILE_NOTIFY_CHANGE_FILE_NAME+ FILE_NOTIFY_CHANGE_DIR_NAME+ FILE_NOTIFY_CHANGE_SIZE ); {Если не удалось получить хэндл - выводим ошибку и прерываем выполнение} Win32Check(ChangeHandle &lt;&gt; INVALID_HANDLE_VALUE); try {выполняем цикл пока} while not Terminated do begin case WaitForSingleObject(ChangeHandle,1000) of WAIT_FAILED: Terminate; {Ошибка, завершаем поток} WAIT_OBJECT_0: {Сообщаем об изменениях}; end; FindNextChangeNotification(ChangeHandle); end; finally FindCloseChangeNotification(ChangeHandle); end; end;

В приведенном выше обработчике Execute мы проводим мониторинг изменения имени файла/директории или размера файла. При этом мы ожидаем любого из заданных в фильтре событий и выводим сообщение. Кстати, создадим событие для вывода сообщения об изменениях, например, такое:

type TChangeMonitor = class(TThread) private [...] FOnChange : TNotifyEvent; procedure DoChange; public [...] property OnChange : TNotifyEvent read FOnChange write FOnChange; protected procedure Execute; override; end;   procedure TChangeMonitor.DoChange; begin if Assigned(FOnChange) then OnChange(Self) end;   procedure TChangeMonitor.Execute; var ChangeHandle: THandle; begin [...] case WaitForSingleObject(ChangeHandle,INFINITE) of WAIT_FAILED: Terminate; //Ошибка, завершаем поток WAIT_OBJECT_0: Synchronize(DoChange); end; [...] end;

Теперь всё готово для проверки работоспособности нашего потока. Создадим новый проект Delphi и на главную форму положим следующие компоненты:

В uses подключим модуль с нашим потоком и объявим следующую переменную:

uses [...], Monitor;   type TForm3 = class(TForm) [...] private FChangeMonitor:TChangeMonitor; public { Public declarations } end;

Теперь напишем необходимые обработчики для событий:

procedure TForm3.Button1Click(Sender: TObject); begin mmLog.Lines.Clear; {создаем поток} FChangeMonitor:=TChangeMonitor.Create(True,edPath.Text,CheckBox1.Checked); {определяем обработчик события} FChangeMonitor.OnChange:=OnChange; {запускаем поток на выполнение} FChangeMonitor.Start; Button1.Enabled:=False; Button2.Enabled:=True; end;   procedure TForm3.Button2Click(Sender: TObject); begin {останавливаем поток} FChangeMonitor.Terminate; Button1.Enabled:=True; Button2.Enabled:=False; end;   procedure TForm3.FormClose(Sender: TObject; var Action: TCloseAction); begin if Assigned(FChangeMonitor) then FChangeMonitor.Terminate; end;   procedure TForm3.OnChange(Sender: TObject); const cLogStr = '%s - Изменения в директории'; begin {выводим сообщение в лог} mmLog.Lines.Add(Format(cLogStr,[DateTimeToStr(Now)])) end;

Запускаем программу, выбираем директорию за которой необходимо следить и нажимаем кнопку “Следить”. Теперь попробуем скопировать/удалить какой-нибудь файл и увидим в Memo соответствующее сообщение.
Приведенный выше пример является, наверное, самым простым, когда мы отслеживаем всего лишь одно событие по которому просто констатируем факт – произошли изменения в директории. А какие изменения – об этом мы ничего не сообщаем. Мы даже не можем в этом случае сказать, что именно произошло. Можно слегка подкорректировать приведенный выше обработчик и, используя приведенные выше функции Windows определить различные события на каждый вариант изменений, используя при этом вместо функции WaitForSingleObject функцию WaitForMultipleObjects. Но об этом, а также об использовании методов CreateFile и ReadDirectoryChangesW мы поговорим в следующий раз.

4.3 3 голоса

Рейтинг статьи

Как узнать, существует ли компонент delphi в вашем приложении? -delphi

Переполнение стека
  1. Около
  2. Продукты
  3. Для команд
  1. Переполнение стека Общественные вопросы и ответы
  2. Переполнение стека для команд Где разработчики и технологи делятся частными знаниями с коллегами
.

c ++ - Как определить, существует ли файл без сбоев из-за проблем с разрешениями?

Переполнение стека
  1. Около
  2. Продукты
  3. Для команд
  1. Переполнение стека Общественные вопросы и ответы
.

java, как проверить, существует ли файл и открыть его?

Переполнение стека
  1. Около
  2. Продукты
  3. Для команд
  1. Переполнение стека Общественные вопросы и ответы
  2. Переполнение стека для команд Где разработчики и технологи делятся частными знаниями с коллегами
.

delphi - Проверить, существует ли поток по его дескриптору

Переполнение стека
  1. Около
  2. Продукты
  3. Для команд
  1. Переполнение стека Общественные вопросы и ответы
  2. Переполнение стека для команд Где разработчики и технологи делятся частными знаниями с коллегами
  3. Вакансии Программирование и связанные с ним технические возможности карьерного роста
  4. Талант Нанимайте технических специалистов и создавайте свой бренд работодателя
.

linux - Как проверить, существуют ли файлы в определенном каталоге в сценарии bash?

Переполнение стека
  1. Около
  2. Продукты
  3. Для команд
  1. Переполнение стека Общественные вопросы и ответы
  2. Переполнение стека для команд Где разработчики и технологи делятся частными знаниями с коллегами
  3. Вакансии Программирование и связанные с ним технические возможности карьерного роста
.

Смотрите также