Начиная с версии XE2 в Delphi появился юнит System.IOUtils, включающий удобные утилиты для работы с файлами и директориями. Предлагаю вместе подробно разобраться с тем, что в юните System.IOUtils имеется и попробовать на примерах как это всё работает.
Всего в юните System.IOUtils вы можете обнаружить три структуры TDirectory, TFile и TPath, содержащие только статические методы. Если вы разрабатываете на .NET, то вы заметите сходство этих трёх структур с классами Directory, File и Path из пространства имён System.IO в .NET. На самом деле в справке Delphi, так и написано, что большинство методов схожи с методами аналогичных классов в .NET. Это даже неплохо, ведь классы Directory, File и Path очень удобные, значит и в Delphi теперь всё должно быть удобно. Но давайте проверять.
Структура TDirectory используется в Delphi для работы с директориями. Она содержит только статические методы. Давайте рассмотрим их.
Начнём наше знакомство со структурой TDirectory, пожалуй, с методов для создания и удаления директории. Для этого есть соответствующие методы CreateDirectory и Delete. Функция CreateDirectory принимает во входном параметре полный путь к директории и создаёт все недостающие в указанном пути папки. Например, если вы хотите создать директорию «Test3», путь к которой должен быть «C:\Test1\Test2\Test3», а у вас на компьютере есть только директория «C:\Test1», которой нет директории «Test2», то функция CreateDirectory создаст сначала директорию «Test2» в директории «Test1», а затем создаст директорию «Test3» в директории «Test2». Т.е. после вызова этой функции у вас будут все три директории, указанные в пути.
Функция Delete удаляет только последнюю директорию, указанную в пути. Например, если у вас на диске «C:» есть директория «Test1», в ней директория «Test2», и в ней директория «Test3», то чтобы удалить директорию «Test3» в функцию Delete нужно передать полный путь к этой директории, в нашем примере это будет «C:\Test1\Test2\Test3». Также функция Delete умеет рекурсивно удалять вложенные директории и файлы, если второй входной параметр установлен в true.
Вот примеры использования функций CreateDirectory и Delete:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils;
begin
try
//Создаём директории Test1, Test2 и Test3, если их нет.
TDirectory.CreateDirectory('C:\Test1\Test2\Test3');
//Удаляем директорию Test3.
TDirectory.Delete('C:\Test1\Test2\Test3');
try
//Удаляем директорию Test1.
//Директория Test1 не пустая, т.к. в ней есть директория Test2.
//Поэтому при вызове метода Delete произойдёт ошибка EInOutError.
TDirectory.Delete('C:\Test1');
except
on ioError: EInOutError do
//Показываем ошибку в консоли.
Writeln(ErrOutput, ioError.Message);
end;
//Удаляем директорию Test1 и рекурсивно все вложенные директории и файлы.
TDirectory.Delete('C:\Test1', true);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Чтобы проверить, существует ли директория, у структуры TDirectory есть функция Exists. Первый параметр функции – это путь к директории. Второй необязательный параметр FollowLink учитывается только при использовании символической ссылки. Если нужно проверить только существование символической ссылки на директорию, то нужно установить этот параметр в false, а если нужно проверить наличие всего сразу, т.е. и символической ссылки на директорию и самой директории, то нужно установить этот параметр в true. Вот примеры использования:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils, Shellapi, Classes, Windows;
var
execInfo: TShellExecuteInfo;
begin
try
//Проверяем, есть ли директория C:\Test1.
//Если директории нет, то функция вернёт false.
Writeln(TDirectory.Exists('C:\Test1'));
//Создаём директорию.
TDirectory.CreateDirectory('C:\Test1');
//Ещё раз проверяем, есть ли директория C:\Test1.
//Теперь директория существует, и функция вернёт true.
Writeln(TDirectory.Exists('C:\Test1'));
//Теперь проверяем, существует ли символическая ссылка C:\TestLink.
//Если ссылка не существует, то функция вернёт false.
Writeln(TDirectory.Exists('C:\TestLink', false));
//Теперь создадим символическую ссылку C:\TestLink на несуществующую директорию C:\Test2.
//Для создания символической ссылки нужно обладать правами администратора,
//поэтому создавать её будем с помощью утилиты командной строки mklink,
//которую будем вызывать от имени администратора.
//Чтобы вызвать эту утилиту, придётся сначала создать пакетный файл,
//а затем выполнить его.
//Итак, сначала создаём пакетный файл с командой mklink.
with TStringList.Create do
try
//Содержимое пакетного файла...
Add('mklink /D C:\TestLink C:\Test2');
//Сохраняем пакетный файл.
SaveToFile('C:\Test1\tmp.bat');
finally
Free;
end;
//Теперь выполняем пакетный файл от имени администратора.
FillChar(execInfo, SizeOf(TShellExecuteInfo), 0);
execInfo.cbSize := SizeOf(TShellExecuteInfo);
execInfo.lpVerb := PWideChar('runas');
execInfo.lpFile := PWideChar('C:\Test1\tmp.bat');
execInfo.fMask := SEE_MASK_NOCLOSEPROCESS;
ShellExecuteEx(@execInfo);
//Ждём, пока пакетный файл отработает.
WaitForSingleObject(execInfo.hProcess, INFINITE);
//Проверяем, существует ли символическая ссылка C:\TestLink.
//Теперь ссылка существует, поэтому функция вернёт true.
Writeln(TDirectory.Exists('C:\TestLink', false));
//Проверяем, существует ли символическая ссылка C:\TestLink
//и директория C:\Test2, на которую она ссылается.
//Ссылка C:\TestLink существует, но директория C:\Test2 - нет,
//поэтому функция вернёт false.
Writeln(TDirectory.Exists('C:\TestLink', true));
//Создаём директорию C:\Test2.
TDirectory.CreateDirectory('C:\Test2');
//Опять проверяем, существует ли символическая ссылка C:\TestLink
//и директория C:\Test2, на которую она ссылается.
//Теперь ссылка C:\TestLink и директория C:\Test2 существуют,
//поэтому функция вернёт true.
Writeln(TDirectory.Exists('C:\TestLink', true));
//Удаляем директорию C:\Test1, а заодно и файл tmp.bat.
TDirectory.Delete('C:\Test1', true);
//Удаляем директорию C:\Test2.
TDirectory.Delete('C:\Test2');
//Удаляем символическую ссылку C:\TestLink.
DeleteFile('C:\TestLink');
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
В структуре TDirectory для чтения и изменения характеристик директории есть следующие методы:
-
-
-
- GetAttributes – возвращает атрибуты папки, такие как «только чтение», «системная», «скрытая» и т.п.;
- SetAttributes – устанавливает новый набор атрибутов директории, такие как «только чтение», «системная», «скрытая» и т.п.;
- GetCreationTime и GetCreationTimeUtc – возвращают дату и время создания директории;
- SetCreationTime и SetCreationTimeUtc – устанавливают дату и время создания директории;
- GetLastAccessTime и GetLastAccessTimeUtc – возвращают дату и время последнего обращения к директории;
- SetLastAccessTime и SetLastAccessTimeUtc – устанавливают дату и время последнего обращения к директории;
- GetLastWriteTime и GetLastWriteTimeUtc – возвращают дату и время последней записи в директорию.
- SetLastWriteTime и SetLastWriteTimeUtc – устанавливают дату и время последней записи в директорию.
Функции, возвращающие и устанавливающие время, в конце имени которых есть суффикс «Utc», возвращают время в формате всемирного координированного времени (UTC).
Теперь рассмотрим примеры:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils, Rtti;
var
fileAttribute: TFileAttribute;
begin
try
//Создаём директории Test1, Test2 и Test3, если их нет.
TDirectory.CreateDirectory('C:\Test1\Test2\Test3');
//Делаем директорию скрытой, выставляя ей атрибут faHidden.
TDirectory.SetAttributes('C:\Test1', [TFileAttribute.faHidden]);
//Делаем директорию доступной только для чтения, выставляя ей атрибут faReadOnly.
TDirectory.SetAttributes('C:\Test1\Test2\Test3', [TFileAttribute.faReadOnly]);
//Отображаем все установленные атрибуты директории Test1.
//В результате отобразятся два атрибута: faHidden и faDirectory.
//Атрибут faDirectory убрать нельзя, он всегда будет присутствовать у директории.
for fileAttribute in TDirectory.GetAttributes('C:\Test1') do
Writeln(TRttiEnumerationType.GetName<TFileAttribute>(fileAttribute));
//Отображаем все установленные атрибуты директории Test3.
//В результате отобразятся два атрибута: faReadOnly и faDirectory.
for fileAttribute in TDirectory.GetAttributes('C:\Test1\Test2\Test3') do
Writeln(TRttiEnumerationType.GetName<TFileAttribute>(fileAttribute));
//Выводим дату и время создания директории Test1.
//В результате отобразится дата и время на момент создания директории.
Writeln(DateTimeToStr(TDirectory.GetCreationTime('C:\Test1')));
//Устанавливаем дату и время создания директории.
TDirectory.SetCreationTime('C:\Test1', StrToDateTime('01.02.03 11:12:13'));
//Выводим дату и время создания директории Test1.
//В результате отобразится 01.02.2003 11:12:13.
Writeln(DateTimeToStr(TDirectory.GetCreationTime('C:\Test1')));
//Выводим дату и время создания директории Test1 в формате UTC, т.е. без учёта часового пояса.
//В результате отобразится 01.02.2003 8:12:13, т.е. -3 часа по Москве.
Writeln(DateTimeToStr(TDirectory.GetCreationTimeUtc('C:\Test1')));
//Выводим дату и время последнего обращения к директории.
Writeln(DateTimeToStr(TDirectory.GetLastAccessTime('C:\Test1')));
//Устанавливаем дату и время последнего обращения к директории.
TDirectory.SetLastAccessTime('C:\Test1', StrToDateTime('01.02.03 11:12:14'));
//Выводим дату и время последнего обращения к директории.
//В результате отобразится 01.02.2003 11:12:14.
Writeln(DateTimeToStr(TDirectory.GetLastAccessTime('C:\Test1')));
//Выводим дату и время последней записи в директорию.
Writeln(DateTimeToStr(TDirectory.GetLastWriteTime('C:\Test1')));
//Устанавливаем дату и время последней записи в директорию.
TDirectory.SetLastWriteTime('C:\Test1', StrToDateTime('01.02.03 11:12:15'));
//Выводим дату и время последней записи в директорию.
//В результате отобразится 01.02.2003 11:12:15.
Writeln(DateTimeToStr(TDirectory.GetLastWriteTime('C:\Test1')));
//Удаляем директорию Test1 и рекурсивно все вложенные директории и файлы.
TDirectory.Delete('C:\Test1', true);
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Для копирования директории у структуры TDirectory есть метод Copy, а для перемещения или переименования – метод Move. Перечисленные выше операции производятся с директорией в целом, включая вложенные директории и файлы.
Если директория, в которую происходит копирование, уже существует, то произойдёт слияние существующей директории и директории, которую вы копируете. При этом совпадающие файлы в директории назначения будут удалены, а вместо них будут скопированы файлы из директории источника.
Вот пример использования методов Copy и Move:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils;
begin
try
//Создаём директории Test1, Test2 и Test3, если их нет.
TDirectory.CreateDirectory('C:\Test1\Test2\Test3');
//Копируем директорию Test1 в директорию Test1.1, включая все вложенные директории и файлы.
TDirectory.Copy('C:\Test1', 'C:\Test1.1');
//Переименовываем директорию Test1 в директорию Test1.2.
TDirectory.Move('C:\Test1', 'C:\Test1.2');
//Перемещаем директорию Test1.2 в директорию C:\Users\Public\Documents.
TDirectory.Move('C:\Test1.2', 'C:\Users\Public\Documents\Test1.2');
//Удаляем директории.
TDirectory.Delete('C:\Test1.1', true);
TDirectory.Delete('C:\Users\Public\Documents\Test1.2', true);
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Чтобы получить список всех файлов и поддиректорий, находящихся внутри какой-либо директории у структуры TDirectory есть методы GetFiles, GetDirectories и GetFileSystemEntries. Метод GetFiles возвращает только файлы, метод GetDirectories – только поддиректории, метод GetFileSystemEntries возвращает и файлы и директории. Каждый из этих методов поддерживает шаблоны поиска и фильтры и может работать рекурсивно.
Кроме того здесь стоит упомянуть и о функции IsEmpty, которая проверяет, пустая директория или нет.
Вот примеры использования методов GetFiles, GetDirectories, GetFileSystemEntries и IsEmpty:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils, Types, DateUtils;
var
s: string;
function FilterBySize(const Path: string;
const SearchRec: TSearchRec): boolean;
begin
//Возвращаем true, если размер файла меньше 50 Кбайт.
Result := SearchRec.Size < 51200;
end;
function FilterByDateTime(const Path: string;
const SearchRec: TSearchRec): boolean;
begin
//Возвращаем true, если у файла или директории
//дата и время последнего изменения старше 2-х лет.
Result := SearchRec.TimeStamp < IncYear(Now, -2);
end;
begin
try
//Ищеи и отображаем все файлы в директории C:\Windows.
for s in TDirectory.GetFiles('C:\Windows') do
Writeln(s);
//Ищем и отображаем все исполняемые файлы в директории C:\Windows.
for s in TDirectory.GetFiles('C:\Windows', '*.exe') do
Writeln(s);
//Рекурсивно ищем и отображаем все файлы
//в директории C:\Users\Public\Pictures.
for s in TDirectory.GetFiles('C:\Users\Public\Pictures', '*',
TSearchOption.soAllDirectories) do
Writeln(s);
//Рекурсивно ищем и отображаем все файлы с расширением .jpg
//в директории C:\Users\Public\Pictures.
for s in TDirectory.GetFiles('C:\Users\Public\Pictures', '*.jpg',
TSearchOption.soAllDirectories) do
Writeln(s);
//Рекурсивно ищем и отображаем все файлы размером меньше 50 Кбайт
//в директории C:\Users\Public\Pictures.
//Для проверки размера используется функция-фильтр FilterBySize.
for s in TDirectory.GetFiles('C:\Users\Public\Pictures', '*',
TSearchOption.soAllDirectories, FilterBySize) do
Writeln(s);
//Рекурсивно ищем и отображаем все файлы
//в директории C:\Users\Public\Pictures, которые не изменялись более 2-х лет.
//Для проверки размера используется функция-фильтр FilterByDateTime.
for s in TDirectory.GetFiles('C:\Users\Public\Pictures', '*',
TSearchOption.soAllDirectories, FilterByDateTime) do
Writeln(s);
//Ищем и отображаем все поддиректории в директории C:\Windows.
for s in TDirectory.GetDirectories('C:\Windows') do
Writeln(s);
//Ищем и отображаем все поддиректории, имя которых начинается с буквы s,
//в директории C:\Windows.
for s in TDirectory.GetDirectories('C:\Windows', 's*') do
Writeln(s);
//Рекурсивно ищем и отображаем все поддиректории
//в директории C:\Users\Public\Pictures.
for s in TDirectory.GetDirectories('C:\Users\Public\Pictures', '*',
TSearchOption.soAllDirectories) do
Writeln(s);
//Рекурсивно ищем и отображаем все поддиректории
//в директории C:\Users\Public\Pictures, которые не изменялись более 2-х лет.
//Для проверки размера используется функция-фильтр FilterByDateTime.
for s in TDirectory.GetDirectories('C:\Users\Public\Pictures', '*',
TSearchOption.soAllDirectories, FilterByDateTime) do
Writeln(s);
//Ищем и отображаем все файлы и поддиректории в директории C:\Windows.
for s in TDirectory.GetFileSystemEntries('C:\Windows') do
Writeln(s);
//Ищем и отображаем все файлы и поддиректории,
//имя которых начинается с буквы s, в директории C:\Windows.
for s in TDirectory.GetFileSystemEntries('C:\Windows', 's*') do
Writeln(s);
//Рекурсивно ищем и отображаем все файлы и поддиректории
//в директории C:\Users\Public\Pictures.
for s in TDirectory.GetFileSystemEntries('C:\Users\Public\Pictures',
TSearchOption.soAllDirectories, nil) do
Writeln(s);
//Рекурсивно ищем и отображаем все файлы и поддиректории
//в директории C:\Users\Public\Pictures, которые не изменялись более 2-х лет.
//Для проверки размера используется функция-фильтр FilterByDateTime.
for s in TDirectory.GetFileSystemEntries('C:\Users\Public\Pictures',
TSearchOption.soAllDirectories, FilterByDateTime) do
Writeln(s);
//Рекурсивно ищем и отображаем все пустые поддиректории
//в директории C:\Users\Public\Pictures.
for s in TDirectory.GetDirectories('C:\Users\Public\Pictures', '*',
TSearchOption.soAllDirectories) do
if TDirectory.IsEmpty(s) then
Writeln(s);
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Путь, который определяет местоположение директории, может сказать о многом. Из него, например, можно получить корневую директорию с помощью функции GetDirectoryRoot. В нём можно найти все родительские директории с помощью рекурсивного вызова функции GetParent. Иногда путь может быть относительным, что вы сможете легко проверить с помощью функции IsRelativePath.
Дополнительно может пригодиться функция GetLogicalDrives, возвращающая список всех логических дисков на компьютере.
Вот примеры использования этих функций:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils;
var
s: string;
begin
try
//Узнаём корневую директорию для директории C:\Users\Public\Pictures.
//В результате мы получим 'C:\'.
Writeln(TDirectory.GetDirectoryRoot('C:\Users\Public\Pictures'));
//Узнаём корневую директорию для сетевой папки \\my-server\Shared\Music.
//В результате мы получим '\\my-server\Shared'.
Writeln(TDirectory.GetDirectoryRoot('\\my-server\Shared\Music'));
//Узнаём корневую директорию для сетевой папки \\192.168.1.100\Shared\Docs.
//В результате мы получим '\\192.168.1.100\Shared'.
Writeln(TDirectory.GetDirectoryRoot('\\192.168.1.100\Shared\Docs'));
//Рекурсивно выводим все родительские директории
//для директории C:\Users\Public\Pictures.
//В результате мы получим:
//'C:\Users\Public'
//'C:\Users'
//'C:\'
s := 'C:\Users\Public\Pictures';
while not TDirectory.GetParent(s).IsEmpty do
begin
s := TDirectory.GetParent(s);
Writeln(s);
end;
//Узнаём, является ли путь относительным.
//В результате получим FALSE.
Writeln(TDirectory.IsRelativePath('C:\Users\Public\Pictures'));
//В результате получим TRUE.
Writeln(TDirectory.IsRelativePath('.\Public\Pictures'));
//В результате получим TRUE.
Writeln(TDirectory.IsRelativePath('..\Shared\Music'));
//Узнаём, какие логические диски есть на ПК.
//Если у вас три диска C:, D: и F:, то результат будет таким:
//'C:\'
//'D:\'
//'F:\'
for s in TDirectory.GetLogicalDrives do
Writeln(s);
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Кроме всего вышеперечисленного у структуры TDirectory есть функции для получения и изменения текущей директории приложения: GetCurrentDirectory и SetCurrentDirectory. Вот примеры использования:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils;
var
s: string;
begin
try
//Получаем тукущую директорию приложения.
Writeln(TDirectory.GetCurrentDirectory);
//Задаём другую текущую директорию приложения.
TDirectory.SetCurrentDirectory('C:\Users\Public\Pictures');
//Ещё раз получаем тукущую директорию приложения.
//Теперь это будет C:\Users\Public\Pictures.
Writeln(TDirectory.GetCurrentDirectory);
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Структура TFile используется в Delphi для работы с файлами. Она содержит только статические методы. Давайте рассмотрим их.
Для создания файла у структуры TFile есть несколько методов:
-
-
-
- Create – создаёт пустой файл и возвращает ассоциированный с ним поток (экземпляр TFileStream), в который сразу можно записывать какие-либо данные.
- CreateText – создаёт пустой файл и возвращает экземпляр объекта TStreamWriter для записи текста в файл.
- CreateSymLink – создаёт символическую ссылку (которая, по сути, тоже является файлом) для папки или файла. Обратите внимание, что для создания символической ссылки, ваше приложение должно выполняться с правами администратора.
Для удаления файла есть функция Delete.
Рассмотрим примеры:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils, Classes;
var
fileStream: TFileStream;
bytes: TBytes;
streamWriter: TStreamWriter;
begin
try
//Создаём временную директорию.
TDirectory.CreateDirectory('C:\Test1');
//Создаём файл test.dat.
fileStream := TFile.Create('C:\Test1\test.dat');
try
bytes := [1, 2, 3];
//Записываем в файл данные из массива bytes.
fileStream.Write(bytes, Length(bytes));
finally
//Удаляем поток.
fileStream.Free;
end;
//Удаляем файл test.dat.
TFile.Delete('C:\Test1\test.dat');
//Создаём текстовый файл test.txt.
streamWriter := TFile.CreateText('C:\Test1\test.txt');
try
//Записываем текст.
streamWriter.Write('Здравствуй, мир!');
finally
//Удаляем писателя.
streamWriter.Free;
end;
//Удаляем файл test.txt.
TFile.Delete('C:\Test1\test.txt');
//Создаём символическую ссылку.
if not TFile.CreateSymLink('C:\Test1\test', 'C:\Test1\test.txt') then
//Если символическая ссылка не создалась, выдаём ошибку.
RaiseLastOSError;
//Удаляем символическую ссылку test.
TFile.Delete('C:\Test1\test');
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
//Удаляем директорию.
TDirectory.Delete('C:\Test1');
Readln;
end.
У структуры TFile есть очень удобные методы, позволяющие делать запись в файл и чтение из него, всего в одну строчку. Вот эти методы:
-
-
-
- WriteAllBytes – записывает массив байт в файл. Если указанный файл существует, то он будет перезаписан.
- WriteAllLines – записывает все строки из массива строк в файл. Если указанный файл существует, то он будет перезаписан. Метод умеет конвертировать записываемый текст в нужную кодировку. Если указана кодировка и она не ANSI, то метод записывает маркер последовательности байтов (BOM).
- WriteAllText – записывает одну строку в файл. Если указанный файл существует, то он будет перезаписан. Метод умеет конвертировать записываемый текст в нужную кодировку. Также метод умеет записывать маркер последовательности байтов (BOM).
- AppendAllText – добавляет текст в конец файла. Если файла нет, то он будет создан.
- ReadAllBytes – считывает файл в новый массив байт.
- ReadAllLines – считывает все строки из файла в массив строк. Метод умеет считывать текст в заданной кодировке.
- ReadAllText – считывает весь текст из файла. Метод умеет считывать текст в заданной кодировке.
Вот примеры использования методов WriteAllText, ReadAllText и AppendAllText:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils, Types;
begin
try
//Создаём директорию C:\Test1.
TDirectory.CreateDirectory('C:\Test1');
//Записываем текст в файл в кодировке UTF-8 без BOM.
TFile.WriteAllText('C:\Test1\test.txt', 'Тест!');
//Считываем текст из файла.
//В результате мы увидим 'РўРчС?С'!', т.к. текст считался в неправильной кодировке.
//Это происходит из-за того, что файл записан в кодировке UTF-8,
//и т.к. BOM отсутствует, то при считывании используется кодировка ANSI.
Writeln(TFile.ReadAllText('C:\Test1\test.txt'));
//Считываем текст из файла и укажем нужную кодировку.
//В результате мы увидим 'Тест!', т.е. теперь текст считался в правильной кодировке.
Writeln(TFile.ReadAllText('C:\Test1\test.txt', TEncoding.UTF8));
//Теперь записываем текст в файл в кодировке ANSI, в которой локаль зависит
//от выставленной локали на вашем компьютере.
//При записи в этой кодировке, файл запишется без BOM.
TFile.WriteAllText('C:\Test1\test.txt', 'Тест!', TEncoding.ANSI);
//Считываем текст из файла.
//В результате мы увидим 'Тест!'. В файле нет BOM,
//поэтому файл считывается в кодировке ANSI,
//т.е. как раз в той, в которой мы его записали.
Writeln(TFile.ReadAllText('C:\Test1\test.txt'));
//Теперь записываем текст в файл в кодировке UTF-8 с BOM.
TFile.WriteAllText('C:\Test1\test.txt', 'Тест!', TEncoding.UTF8);
//Считываем текст из файла.
//В результате мы увидим 'Тест!'.
//В отличие от первого примера здесь кодировка берётся из BOM,
//т.е. в нашем случае UTF-8, поэтому текст считывается корректно.
Writeln(TFile.ReadAllText('C:\Test1\test.txt'));
//Добавляем в конец файла текст.
//При добавлении будет использована кодировка, указанная в BOM.
//Если BOM нет, то будет использована кодировка ANSI.
TFile.AppendAllText('C:\Test1\test.txt', ' Тест2!');
//Считываем текст из файла.
//В результате мы увидим 'Тест! Тест2!'.
Writeln(TFile.ReadAllText('C:\Test1\test.txt'));
//Удаляем директорию C:\Test1 и все файлы в ней.
TDirectory.Delete('C:\Test1', true);
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Вот примеры использования методов WriteAllLines, ReadAllLines и AppendAllText:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils, Types;
var
s: string;
begin
try
//Создаём директорию C:\Test1.
TDirectory.CreateDirectory('C:\Test1');
//Записываем три строки в текстовый файл в кодировке UTF-8 без BOM.
TFile.WriteAllLines('C:\Test1\test2.txt',
['Строка 1', 'Строка 2', 'Строка 3']);
//Читаем строки из файла. В результате получим:
//РЎС'С?Р?РєР° 1
//РЎС'С?Р?РєР° 2
//РЎС'С?Р?РєР° 3
//Как видим строки считываются в неправильной кодировке.
//Это происходит из-за того, что файл записан в кодировке UTF-8,
//и т.к. BOM отсутствует, то при считывании используется кодировка ANSI.
for s in TFile.ReadAllLines('C:\Test1\test2.txt') do
Writeln(s);
//Теперь читаем строки из файла в нужной кодировке. Результат будет:
//Строка 1
//Строка 2
//Строка 3
for s in TFile.ReadAllLines('C:\Test1\test2.txt', TEncoding.UTF8) do
Writeln(s);
//Теперь записываем строки в файл в кодировке ANSI, в которой локаль зависит
//от выставленной локали на вашем компьютере.
//При записи в этой кодировке, файл запишется без BOM.
TFile.WriteAllLines('C:\Test1\test2.txt',
['Строка 1', 'Строка 2', 'Строка 3'], TEncoding.ANSI);
//Ещё раз считываем строки из файла. В результате получим:
//Строка 1
//Строка 2
//Строка 3
//В файле нет BOM, поэтому файл считывается в кодировке ANSI,
//т.е. как раз в той, в которой мы его записали.
for s in TFile.ReadAllLines('C:\Test1\test2.txt') do
Writeln(s);
//Теперь записываем строки в файл в кодировке UTF-8 с BOM.
TFile.WriteAllLines('C:\Test1\test2.txt',
['Строка 1', 'Строка 2', 'Строка 3'], TEncoding.UTF8);
//Считываем строки из файла. В результате увидим:
//Строка 1
//Строка 2
//Строка 3
//В отличие от первого примера здесь кодировка берётся из BOM,
//т.е. в нашем случае UTF-8, поэтому строки считываются корректно.
for s in TFile.ReadAllLines('C:\Test1\test2.txt') do
Writeln(s);
//Добавляем в конец файла ещё две строки (строки разделяются символами #13#10).
//При добавлении будет использована кодировка, указанная в BOM.
//Если BOM нет, то будет использована кодировка ANSI.
TFile.AppendAllText('C:\Test1\test2.txt', 'Строка 4'#13#10'Строка 5'#13#10);
//Считываем строки из файла. В результате увидим:
//Строка 1
//Строка 2
//Строка 3
//Строка 4
//Строка 5
for s in TFile.ReadAllLines('C:\Test1\test2.txt') do
Writeln(s);
//Удаляем директорию C:\Test1 и все файлы в ней.
TDirectory.Delete('C:\Test1', true);
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
А вот примеры использования функций WriteAllBytes и ReadAllBytes:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils, Types;
var
b: byte;
begin
try
//Создаём директорию C:\Test1.
TDirectory.CreateDirectory('C:\Test1');
//Записываем массив из четырёх байт в файл.
TFile.WriteAllBytes('C:\Test1\test.dat', [0, 100, 200, 255]);
//Считываем байты из файла. В результате увидим в консоли:
//0
//100
//200
//255
for b in TFile.ReadAllBytes('C:\Test1\test.dat') do
Writeln(b);
//Удаляем директорию C:\Test1 и все файлы в ней.
TDirectory.Delete('C:\Test1', true);
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Теперь рассмотрим ещё на несколько удобных функций для открытия файла. Это функции AppendText, OpenText, Open, OpenRead, OpenWrite.
Функции AppendText и OpenText предназначены для работы с текстовыми файлами в кодировке UTF-8. AppendText открывает файл, или создаёт новый файл, если его не было, для добавления в него текста, а OpenText – для чтения из текстового файла. Функция AppendText для работы с файлом, создаёт и возвращает объект TStreamWriter, который после использования нужно удалить. Функция OpenText для чтения текста создаёт и возвращает объект TStreamReader, который после использования также нужно удалить.
Функции Open, OpenRead, OpenWrite по сути просто создают объект TFileStream и возвращают его. Функция OpenRead открывает файл на чтение, функция OpenWrite - на запись, а функция Open может, как создавать файлы, так и открывать их в различных режимах и с различными привилегиями.
Рассмотрим примеры использования этих функций:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils, Classes;
var
streamWriter: TStreamWriter;
streamReader: TStreamReader;
fileStream: TFileStream;
bytes: TBytes;
b: byte;
begin
try
//Создаём временную директорию.
TDirectory.CreateDirectory('C:\Test1');
//Создаём текстовый файл test.txt в кодировке UTF-8 и добавляем в две строки текста.
streamWriter := TFile.AppendText('C:\Test1\test.txt');
try
streamWriter.Write('Привет, мир!');
streamWriter.WriteLine;
streamWriter.Write('Это вторая строка в тексте.');
finally
streamWriter.Free;
end;
//Открываем текстовый файл в кодировке UTF-8 на чтение, и считываем две строки текста.
streamReader := TFile.OpenText('C:\Test1\test.txt');
try
Writeln('1-я строка: ' + streamReader.ReadLine);
Writeln('2-я строка: ' + streamReader.ReadLine);
finally
streamReader.Free;
end;
//Создаём файл функцией Open и записываем 3 байта.
fileStream := TFile.Open('C:\Test1\test.dat', TFileMode.fmCreate, TFileAccess.faWrite);
try
bytes := [10, 20, 30];
fileStream.Write(bytes, 3);
finally
fileStream.Free;
end;
//Дописываем в файл ещё 3 байта функцией OpenWrite.
fileStream := TFile.OpenWrite('C:\Test1\test.dat');
try
bytes := [40, 50, 60];
fileStream.Seek(0, TSeekOrigin.soEnd);
fileStream.Write(bytes, 3);
finally
fileStream.Free;
end;
//Читаем из файла все байты функцией OpenRead.
fileStream := TFile.OpenRead('C:\Test1\test.dat');
try
SetLength(bytes, fileStream.Size);
fileStream.Read(bytes, fileStream.Size);
for b in bytes do
Writeln(b);
finally
fileStream.Free;
end;
//Удаляем директорию C:\Test1 и все файлы в ней.
TDirectory.Delete('C:\Test1', true);
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Так же как и у TDirectory у структуры TFile есть функция Exists. Первый параметр функции – это путь к файлу. Второй необязательный параметр FollowLink учитывается только при использовании символической ссылки. Если нужно проверить только существование символической ссылки на файл, то нужно установить этот параметр в false, а если нужно проверить наличие всего сразу, т.е. и символической ссылки на файл и самого файла, то нужно установить этот параметр в true. Вот примеры использования:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils, ShellAPI, Classes, Windows;
var
execInfo: TShellExecuteInfo;
begin
try
//Проверяем, есть ли файл.
//Если файла нет, то функция вернёт false.
Writeln(TFile.Exists('C:\Test1\test1.txt'));
//Создаём директорию C:\Test1.
TDirectory.CreateDirectory('C:\Test1');
//Создаём файл test.txt.
TFile.CreateText('C:\Test1\test1.txt').Free;
//Проверяем, есть ли файл ещё раз.
//Теперь файл точно есть, поэтому функция вернёт true.
Writeln(TFile.Exists('C:\Test1\test1.txt'));
//Теперь проверяем, существует ли символическая ссылка C:\Test1\TestLink.
//Если ссылка не существует, то функция вернёт false.
Writeln(TFile.Exists('C:\Test1\TestLink', false));
//Создадим символическую ссылку C:\Test1\TestLink на несуществующий файл C:\Test1\test2.txt.
//Для создания символической ссылки нужно обладать правами администратора,
//поэтому создавать её будем с помощью утилиты командной строки mklink,
//которую будем вызывать от имени администратора.
//Чтобы вызвать эту утилиту, придётся сначала создать пакетный файл,
//а затем выполнить его.
//Итак, сначала создаём пакетный файл с командой mklink.
TFile.WriteAllText('C:\Test1\tmp.bat', 'mklink C:\Test1\TestLink C:\Test1\test2.txt');
//Теперь выполняем пакетный файл от имени администратора.
FillChar(execInfo, SizeOf(TShellExecuteInfo), 0);
execInfo.cbSize := SizeOf(TShellExecuteInfo);
execInfo.lpVerb := PWideChar('runas');
execInfo.lpFile := PWideChar('C:\Test1\tmp.bat');
execInfo.fMask := SEE_MASK_NOCLOSEPROCESS;
ShellExecuteEx(@execInfo);
//Ждём, пока пакетный файл отработает.
WaitForSingleObject(execInfo.hProcess, INFINITE);
//Проверяем, существует ли символическая ссылка C:\Test1\TestLink.
//Теперь ссылка существует, поэтому функция вернёт true.
Writeln(TFile.Exists('C:\Test1\TestLink', false));
//Проверяем, существует ли символическая ссылка C:\Test1\TestLink
//и файл C:\Test1\test2.txt, на которую она ссылается.
//Ссылка C:\Test1\TestLink существует, но файл C:\Test1\test2.txt - нет,
//поэтому функция вернёт false.
Writeln(TFile.Exists('C:\Test1\TestLink', true));
//Создаём файл C:\Test1\test2.txt.
TFile.Create('C:\Test1\test2.txt').Free;
//Опять проверяем, существует ли символическая ссылка C:\Test1\TestLink
//и файл C:\Test1\test2.txt, на которую она ссылается.
//Теперь ссылка C:\Test1\TestLink и файл C:\Test1\test2.txt существуют,
//поэтому функция вернёт true.
Writeln(TFile.Exists('C:\Test1\TestLink', true));
//Удаляем символическую ссылку.
TFile.Delete('C:\Test1\TestLink');
//Удаляем директорию C:\Test1 и все файлы в ней.
TDirectory.Delete('C:\Test1', true);
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Чуть выше мы упоминали работу с символической ссылкой, а теперь разберёмся, как узнать, на что ссылается символическая ссылка. Для этого у структуры TFile есть две функции с именем GetSymLinkTarget. Вот пример:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils, ShellAPI, Windows;
var
execInfo: TShellExecuteInfo;
fileName: string;
symLinkRec: TSymLinkRec;
begin
try
//Создаём временную директорию.
TDirectory.CreateDirectory('C:\Test1');
//Создаём текстовый файл test.txt.
TFile.WriteAllText('C:\Test1\test.txt', 'Здравствуй, мир!');
//Создаём символическую ссылку test, которая будет ссылаться на файл test.txt.
//Для создания символической ссылки нужно обладать правами администратора,
//поэтому создавать её будем с помощью утилиты командной строки mklink,
//которую будем вызывать от имени администратора.
//Чтобы вызвать эту утилиту, придётся сначала создать пакетный файл,
//а затем выполнить его.
//Итак, сначала создаём пакетный файл с командой mklink.
TFile.WriteAllText('C:\Test1\tmp.bat', 'mklink C:\Test1\test C:\Test1\test.txt');
//Теперь выполняем пакетный файл от имени администратора.
FillChar(execInfo, SizeOf(TShellExecuteInfo), 0);
execInfo.cbSize := SizeOf(TShellExecuteInfo);
execInfo.lpVerb := PWideChar('runas');
execInfo.lpFile := PWideChar('C:\Test1\tmp.bat');
execInfo.fMask := SEE_MASK_NOCLOSEPROCESS;
ShellExecuteEx(@execInfo);
//Ждём, пока пакетный файл отработает.
WaitForSingleObject(execInfo.hProcess, INFINITE);
//Получаем имя файла, на который ссылается символическая ссылка.
TFile.GetSymLinkTarget('C:\Test1\test', fileName);
//Выводим, полученное имя файла. В результате увидим 'C:\Test1\test'.
Writeln(fileName);
//Получаем все характеристики символической ссылки.
TFile.GetSymLinkTarget('C:\Test1\test', symLinkRec);
//Выводим некоторые поля структуры symLinkRec.
//Имя целевой папки или файла.
Writeln(symLinkRec.TargetName);
//Атрибуты целевого файла.
Writeln(symLinkRec.Attr);
//Размер целевого файла.
Writeln(symLinkRec.Size);
//Время и дата создания целевого файла или папки.
Writeln(FormatDateTime('dd.mm.yyyy hh:nn:ss:', symLinkRec.TimeStamp));
//Удаляем символическую ссылку.
TFile.Delete('C:\Test1\test');
//Удаляем директорию C:\Test1 и все файлы в ней.
TDirectory.Delete('C:\Test1', true);
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
В структуре TFile для чтения и изменения характеристик файла есть следующие методы:
-
-
-
- GetAttributes – возвращает атрибуты файла, такие как «только чтение», «системный», «скрытый» и т.п.;
- SetAttributes – устанавливает новый набор атрибутов для файла, такие как «только чтение», «системный», «скрытый» и т.п.;
- GetCreationTime и GetCreationTimeUtc – возвращают дату и время создания файла;
- SetCreationTime и SetCreationTimeUtc – устанавливают дату и время создания файла;
- GetLastAccessTime и GetLastAccessTimeUtc – возвращают дату и время последнего обращения к файлу;
- SetLastAccessTime и SetLastAccessTimeUtc – устанавливают дату и время последнего обращения к файлу;
- GetLastWriteTime и GetLastWriteTimeUtc – возвращают дату и время последней записи в файл.
- SetLastWriteTime и SetLastWriteTimeUtc – устанавливают дату и время последней записи в файл.
Функции, возвращающие и устанавливающие время, в конце имени которых есть суффикс «Utc», возвращают время в формате всемирного координированного времени (UTC).
Кроме приведённых здесь функций есть ещё недокументированные статические функции IntegerToFileAttributes и FileAttributesToInteger. Первая конвертирует атрибуты операционной системы для файла или директории в атрибуты, описанные в перечислении TFileAttribute, а вторая - обратно.
Рассмотрим примеры:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils, Rtti;
var
fileAttribute: TFileAttribute;
begin
try
//Создаём директорию.
TDirectory.CreateDirectory('C:\Test3');
//Создаём пустые файлы для экспериментов.
TFile.Create('C:\Test3\test1.txt').Free;
TFile.Create('C:\Test3\test2.txt').Free;
//Делаем файл скрытым, выставляя ему атрибут faHidden.
TFile.SetAttributes('C:\Test3\test1.txt', [TFileAttribute.faHidden]);
//Делаем файл доступным только для чтения, выставляя ему атрибут faReadOnly.
TFile.SetAttributes('C:\Test3\test2.txt', [TFileAttribute.faReadOnly]);
//Отображаем все установленные атрибуты файла test1.txt.
//В результате отобразятся атрибут faHidden.
for fileAttribute in TFile.GetAttributes('C:\Test3\test1.txt') do
Writeln(TRttiEnumerationType.GetName<TFileAttribute>(fileAttribute));
//Отображаем все установленные атрибуты файла test2.txt.
//В результате отобразится атрибут faReadOnly.
for fileAttribute in TFile.GetAttributes('C:\Test3\test2.txt') do
Writeln(TRttiEnumerationType.GetName<TFileAttribute>(fileAttribute));
//Выводим дату и время создания файла test1.txt.
//В результате отобразится дата и время на момент создания файла.
Writeln(DateTimeToStr(TFile.GetCreationTime('C:\Test3\test1.txt')));
//Устанавливаем дату и время создания файла.
TFile.SetCreationTime('C:\Test3\test1.txt', StrToDateTime('01.02.03 11:12:13'));
//Выводим дату и время создания файла.
//В результате отобразится 01.02.2003 11:12:13.
Writeln(DateTimeToStr(TFile.GetCreationTime('C:\Test3\test1.txt')));
//Выводим дату и время создания файла в формате UTC, т.е. без учёта часового пояса.
//В результате отобразится 01.02.2003 8:12:13, т.е. -3 часа по Москве.
Writeln(DateTimeToStr(TFile.GetCreationTimeUtc('C:\Test3\test1.txt')));
//Выводим дату и время последнего обращения к файлу.
Writeln(DateTimeToStr(TFile.GetLastAccessTime('C:\Test3\test1.txt')));
//Устанавливаем дату и время последнего обращения к файлу.
TFile.SetLastAccessTime('C:\Test3\test1.txt', StrToDateTime('01.02.03 11:12:14'));
//Выводим дату и время последнего обращения к файлу.
//В результате отобразится 01.02.2003 11:12:14.
Writeln(DateTimeToStr(TFile.GetLastAccessTime('C:\Test3\test1.txt')));
//Выводим дату и время последней записи в файл.
Writeln(DateTimeToStr(TFile.GetLastWriteTime('C:\Test3\test1.txt')));
//Устанавливаем дату и время последней записи в файл.
TFile.SetLastWriteTime('C:\Test3\test1.txt', StrToDateTime('01.02.03 11:12:15'));
//Выводим дату и время последней записи в файл.
//В результате отобразится 01.02.2003 11:12:15.
Writeln(DateTimeToStr(TFile.GetLastWriteTime('C:\Test3\test1.txt')));
//Удаляем директорию и все вложенные файлы.
TDirectory.Delete('C:\Test3', true);
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Для копирования файла у структуры TFile есть метод Copy, а для перемещения или переименования – метод Move.
Метод Copy кидает ошибку, если файл с таким же именем, как файл назначения существует. Однако вы можете установить третий параметр метода Overwrite в true, и тогда операция копирования всё равно выполнится.
Кроме вышеуказанного случая метод Copy кидает ошибку, если файл, который вы хотите копировать, не существует, неверно указан путь или пользователь не имеет достаточных привилегий для копирования файла в указанное место.
Метод Move кидает ошибку, если файл назначения существует.
Вот пример использования методов Copy и Move:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils;
begin
try
//Создаём директории.
TDirectory.CreateDirectory('C:\Test1');
TDirectory.CreateDirectory('C:\Test2');
//Создаём файл.
TFile.Create('C:\Test1\file1.txt').Free;
//Копируем файл в другую директорию.
TFile.Copy('C:\Test1\file1.txt', 'C:\Test2\file1.txt');
//Ещё раз пытаемся скопировать файл, вместо уже существующего.
//При этом мы получим ошибку EInOutError с текстом 'The specified file already exists'.
try
TFile.Copy('C:\Test1\file1.txt', 'C:\Test2\file1.txt');
except
//Отлавливаем ошибку EInOutError и ничего не делаем.
on EInOutError do;
end;
//Опять копируем файл вместо существующего,
//но теперь выставляем параметр Overwrite в true.
//В этом случае существующий файл заменится на новый.
TFile.Copy('C:\Test1\file1.txt', 'C:\Test2\file1.txt', true);
//Переименовываем файл, оставляя его в той же директории.
TFile.Move('C:\Test1\file1.txt', 'C:\Test1\file2.txt');
//Переносим файл в другую директорию.
TFile.Move('C:\Test1\file2.txt', 'C:\Test2\file2.txt');
//Переносим файл в другую директорию и одновременно переименовываем его.
TFile.Move('C:\Test2\file2.txt', 'C:\Test1\file3.txt');
//Удаляем директории и все вложенные файлы.
TDirectory.Delete('C:\Test1', true);
TDirectory.Delete('C:\Test2', true);
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Шифрование и расшифровывание файла можно сделать с помощью, соответственно, методов Encrypt и Decrypt. После шифрования вы сможете работать с файлом как и раньше. Всю работу по чтению из зашифрованного файла, запись в него и т.д. берёт на себя операционная система. Вот пример использования функций.
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils;
begin
try
//Создаём директорию.
TDirectory.CreateDirectory('C:\Test1');
//Создаём файл.
TFile.WriteAllText('C:\Test1\file1.txt', 'Содержимое файла');
//Шифруем файл.
TFile.Encrypt('C:\Test1\file1.txt');
//Расшифровываем файл.
TFile.Decrypt('C:\Test1\file1.txt');
//Удаляем директории и все вложенные файлы.
TDirectory.Delete('C:\Test1', true);
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
У структуры TFile есть метод Replace, позволяющий заменить содержимое файла на содержимое другого файла. По сути, происходит замена одного файла на другой, но при замене сохранятся все атрибуты файла, содержимого которого мы меняем. Атрибуты копируются следующие: время создания, краткое название файла, идентификатор объекта, дискреционный список контроля доступа (DACL), атрибуты безопасности, шифрование, сжатие и именованные потоки (не в заменяемом файле). Однако вы можете сказать функции Replace, что сохранять атрибуты не нужно, в этом случае вы можете установить четвёртый параметр функции IgnoreMetadataErrors в true. Также для заменяемого файла метод Replace создаёт резервную копию.
Вот примеры использования функции Replace:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils;
begin
try
//Создаём директории.
TDirectory.CreateDirectory('C:\Test1');
//Создаём два файла.
TFile.WriteAllText('C:\Test1\file1.txt', 'Содержимое первого файла');
TFile.WriteAllText('C:\Test1\file2.txt', 'Содержимое второго файла');
//Шифруем только второй файл file2.txt.
TFile.Encrypt('C:\Test1\file2.txt');
//Заменяем содержимое файла file2.txt на содержимое файла file1.txt.
//При этом в файл backup.txt отправляется старое содержимое файла file2.txt.
TFile.Replace('C:\Test1\file1.txt', 'C:\Test1\file2.txt', 'C:\Test1\backup.txt');
//После замены содержимого второй файл останется зашифрованным.
//В консоли появится надпись 'Файл file2.txt зашифрован.'.
if TFileAttribute.faEncrypted in TFile.GetAttributes('C:\Test1\file2.txt') then
Writeln('Файл file2.txt зашифрован.');
//Удаляем директории и все вложенные файлы.
TDirectory.Delete('C:\Test1', true);
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Структура TPath используется в Delphi для работы с путями. Она содержит только статические методы и свойства. Давайте рассмотрим их.
При составлении путей к файлам и директориям используются определённые специальные символы, которые могут быть разными в разных операционных системах. Чтобы не ломать голову и не гадать, какие символы для чего нужно использовать, мы можем узнать это у структуры TPath с помощью следующих статических свойств:
-
-
-
- DirectorySeparatorChar – символ для разделения директорий разного уровня;
- AltDirectorySeparatorChar – альтернативный символ для разделения директорий разного уровня;
- ExtensionSeparatorChar – символ для разделения имени от расширения в имени файла;
- PathSeparator – символ для разделения путей в переменных окружения;
- VolumeSeparatorChar – символ для отделения буквы диска от остального пути.
Вот пример, с выводом значений всех свойств TPath:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils;
begin
try
//Результат будет '\'.
Writeln(TPath.DirectorySeparatorChar);
//Результат будет '/'.
Writeln(TPath.AltDirectorySeparatorChar);
//Результат будет '.'.
Writeln(TPath.ExtensionSeparatorChar);
//Результат будет ';'.
Writeln(TPath.PathSeparator);
//Результат будет ':'.
Writeln(TPath.VolumeSeparatorChar);
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
В каждой современной операционной системе есть директории для хранения документов, видео, музыки и т.п. Кроме того есть разнообразные специальные директории для хранения системных библиотек, временных файлов и т.п. Это сделано для удобства пользователей и разработчиков, а также для поддержания порядка. Для получения путей к таким директориям у структуры TPath есть следующие функции:
-
-
-
- GetAlarmsPath – путь к директории для хранения пользовательских звуков для будильника. Если операционная система не поддерживает такую директорию, то эта функция вернёт пустую строку, например, iOS. В Windows и OS X эта функция вернёт то же, что и функция GetMusicPath.
- GetCachePath – путь к директории, в которой ваше приложение может сохранять файлы кеша.
- GetCameraPath – путь к пользовательской директории, в которую сохраняются фотографии, сделанные с помощью камеры устройства. Если операционная система не поддерживает такую директорию, то эта функция вернёт пустую строку, например, iOS. В Windows и OS X эта функция вернёт то же, что и функция GetPicturesPath.
- GetDocumentsPath – путь к директории для хранения документов пользователя.
- GetDownloadsPath – путь к директории для хранения скачанных пользователем файлов. Если операционная система не поддерживает такую директорию, то эта функция вернёт пустую строку, например, iOS.
- GetHomePath – возвращает либо домашний путь пользователя (в Linux - /home/<username>), либо путь к временной папке приложения (В Windows Vista и позже - C:\Users\<username>\AppData\Roaming), либо путь к хранилищу (в Android - /data/data/<application ID>/files).
- GetLibraryPath – путь к директории для хранения данных вашего приложения. Если операционная система не поддерживает такую директорию, то эта функция вернёт пустую строку. Например, для Windows - C:\Program Files\<application folder>, для Android - /data/app-lib/<application ID>.
- GetMoviesPath – путь к директории для хранения видео пользователя. Если операционная система не поддерживает такую директорию, то эта функция вернёт пустую строку, например, iOS.
- GetMusicPath – путь к директории для хранения музыки пользователя. Если операционная система не поддерживает такую директорию, то эта функция вернёт пустую строку, например, iOS.
- GetPublicPath – путь к директории, где можно сохранять данные приложения, доступные другим приложениям. Если операционная система не поддерживает такую директорию, то эта функция вернёт пустую строку, например, iOS. Например, Windows Vista и позже - C:\ProgramData, OS X - /Users/<username>/Public.
- GetPicturesPath – путь к директории для хранения фотографий и картинок пользователя. Если операционная система не поддерживает такую директорию, то эта функция вернёт пустую строку, например, iOS.
- GetRingtonesPath – путь к директории для хранения пользовательских звуков для звонка. Если операционная система не поддерживает такую директорию, то эта функция вернёт пустую строку, например, iOS. В Windows и OS X эта функция вернёт то же, что и функция GetMusicPath.
- GetSharedAlarmsPath – путь к директории для хранения общих звуков для будильника. Если операционная система не поддерживает такую директорию, то эта функция вернёт пустую строку, например, iOS. В Windows и OS X эта функция вернёт то же, что и функция GetSharedMusicPath.
- GetSharedCameraPath – путь к общей директории, в которую сохраняются фотографии, сделанные с помощью камеры устройства. Если операционная система не поддерживает такую директорию, то эта функция вернёт пустую строку, например, iOS. В Windows и OS X эта функция вернёт то же, что и функция GetSharedPicturesPath.
- GetSharedDocumentsPath – путь к общей директории для хранения документов пользователя. Если операционная система не поддерживает такую директорию, то эта функция вернёт пустую строку, например, iOS.
- GetSharedDownloadsPath – путь к общей директории для хранения скачанных файлов. Если операционная система не поддерживает такую директорию, то эта функция вернёт пустую строку, например, iOS.
- GetSharedMoviesPath – путь к общей директории для хранения видео. Если операционная система не поддерживает такую директорию, то эта функция вернёт пустую строку, например, iOS.
- GetSharedMusicPath – путь к общей папки для хранения музыки. Если операционная система не поддерживает такую директорию, то эта функция вернёт пустую строку, например, iOS.
- GetSharedPicturesPath – путь к общей директории для хранения фотографий и картинок. Если операционная система не поддерживает такую директорию, то эта функция вернёт пустую строку, например, iOS.
- GetSharedRingtonesPath – путь к общей папке для хранения звуков для звонка. Если операционная система не поддерживает такую директорию, то эта функция вернёт пустую строку, например, iOS. В Windows и OS X эта функция вернёт то же, что и функция GetSharedMusicPath.
- GetTempPath – путь к папке для хранения временных файлов. Файлы, сохранённые здесь, могут быть удалены после перезагрузки системы или между сессиями приложения.
Вот пример использования функций:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils;
begin
try
//Результат будет: C:\Users\username\Music
Writeln(TPath.GetAlarmsPath);
//Результат будет: C:\Users\username\AppData\Local
Writeln(TPath.GetCachePath);
//Результат будет: C:\Users\username\Pictures
Writeln(TPath.GetCameraPath);
//Результат будет: C:\Users\username\Documents
Writeln(TPath.GetDocumentsPath);
//Результат будет: C:\Users\username\AppData\Local
Writeln(TPath.GetDownloadsPath);
//Результат будет: C:\Users\username\AppData\Roaming
Writeln(TPath.GetHomePath);
//Результат будет: C:\Projects\Delphi\Tokyo\IOUtilsTest\Win32\Debug\
Writeln(TPath.GetLibraryPath);
//Результат будет: C:\Users\username\Videos
Writeln(TPath.GetMoviesPath);
//Результат будет: C:\Users\username\Music
Writeln(TPath.GetMusicPath);
//Результат будет: C:\ProgramData
Writeln(TPath.GetPublicPath);
//Результат будет: C:\Users\username\Pictures
Writeln(TPath.GetPicturesPath);
//Результат будет: C:\Users\username\Music
Writeln(TPath.GetRingtonesPath);
//Результат будет: C:\Users\Public\Music
Writeln(TPath.GetSharedAlarmsPath);
//Результат будет: C:\Users\Public\Pictures
Writeln(TPath.GetSharedCameraPath);
//Результат будет: C:\Users\Public\Documents
Writeln(TPath.GetSharedDocumentsPath);
//Результат будет: C:\ProgramData
Writeln(TPath.GetSharedDownloadsPath);
//Результат будет: C:\Users\Public\Videos
Writeln(TPath.GetSharedMoviesPath);
//Результат будет: C:\Users\Public\Music
Writeln(TPath.GetSharedMusicPath);
//Результат будет: C:\Users\Public\Pictures
Writeln(TPath.GetSharedPicturesPath);
//Результат будет: C:\Users\Public\Music
Writeln(TPath.GetSharedRingtonesPath);
//Результат будет: c:\temp\
Writeln(TPath.GetTempPath);
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
У структуры TPath есть много методов для работы с путями, например, для соединения путей или для разбивки:
-
-
-
- ChangeExtension – изменяет расширение файла в указанном пути. Функция не меняет имя реального файла, она только возвращает новую получившуюся строку.
- Combine – соединяет два пути в один. Например, если в первом параметре указан абсолютный путь к директории (например, C:\Test1), а во втором – имя файла (например, test.txt), то в результате функция вернёт абсолютный путь к файлу (получим C:\Test1\test.txt). Если во втором параметре указан абсолютный путь, то функция просто вернёт его, игнорируя первый параметр.
- GetDirectoryName – извлекает путь к директории из пути к файлу. Например, для пути «C:\MyApp\Temp\temp.txt» функция вернёт «C:\MyApp\Temp». Функция вернёт пустую строку, если в пути к файлу нет части с диском и директорией, например, если вы передадите в функцию строку «test.txt».
- GetExtendedPrefix – возвращает расширенный тип префикса для указанного пути, если он есть. Возможные варианты \\?\ или \\?\UNC\.
- GetExtension – извлекает расширение файла из пути. Результат содержит точку в начале строки. Если у имени файла нет расширения, то функция вернёт пустую строку.
- GetFileName – извлекает имя файла с расширением из пути к файлу. Например, для пути «C:\Test1\test.txt» функция вернёт «test.txt».
- GetFileNameWithoutExtension – извлекает имя файла без расширения из пути к файлу. Например, для пути «C:\Test1\test.txt» функция вернёт «test».
- GetFullPath – возвращает абсолютный путь для указанного относительного пути. При создании абсолютного пути функция использует текущую директорию. Например, если текущая директория «C:\MyApp», то для пути «\Temp\test.txt», функция вернёт «C:\MyApp\Temp\test.txt». Если вы передали в функцию абсолютный путь, то функция вернёт его без изменений.
- GetPathRoot – возвращает корень для указанного пути. Например, для пути «C:\MyApp\Temp», функция вернёт «C:\».
- HasExtension – функция проверяет, есть ли у указанного имени файла расширение.
- HasValidFileNameChars – функция проверяет, содержит ли имя файла или шаблон имени файла только разрешённые символы.
- HasValidPathChars – функция проверяет, содержит ли путь только разрешённые символы.
- IsDriveRooted – функция проверяет, является ли путь абсолютным и содержит ли букву логического диска.
- IsExtendedPrefixed – функция проверяет, содержит ли путь расширенный префикс.
- IsPathRooted – проверяет, является ли путь абсолютным.
- IsRelativePath – проверяет, является ли путь относительным.
- IsUNCPath – проверяет, указан ли путь в UNC (Universal Naming Convention) формате. Путь в формате UNC начинается с двух слешей, например, «\\computer\folder».
- IsUNCRooted – проверяет, указан ли корень в пути в формате UNC.
- MatchesPattern – проверяет соответствие имени файла шаблону.
Вот примеры использования функций для работы с путями:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils, Rtti;
begin
try
//Меняем расширение файла. Результат будет 'C:\MyApp\Temp\temp.dat'.
Writeln(TPath.ChangeExtension('C:\MyApp\Temp\temp.txt', '.dat'));
//Соединяем два пути. Результат будет 'C:\MyApp\Temp\temp.txt'.
Writeln(TPath.Combine('C:\MyApp\', 'Temp\temp.txt'));
//Извлекаем путь к директории. Результат будет 'C:\MyApp\Temp'.
Writeln(TPath.GetDirectoryName('C:\MyApp\Temp\temp.txt'));
//Получаем тип расширенного префикса.
//Результат будет pptNoPrefix.
Writeln(TRttiEnumerationType.GetName<TPathPrefixType>(
TPath.GetExtendedPrefix('C:\MyApp\Temp\temp.txt')));
//Результат будет pptExtended.
Writeln(TRttiEnumerationType.GetName<TPathPrefixType>(
TPath.GetExtendedPrefix('\\?\C:\MyApp\Temp\temp.txt')));
//Результат будет pptExtendedUNC.
Writeln(TRttiEnumerationType.GetName<TPathPrefixType>(
TPath.GetExtendedPrefix('\\?\UNC\my_computer\shared_folder')));
//Извлекаем расширение файла. Результат будет '.txt'.
Writeln(TPath.GetExtension('C:\MyApp\Temp\temp.txt'));
//Извлекаем имя файла с расширением. Результат будет 'temp.txt'.
Writeln(TPath.GetFileName('C:\MyApp\Temp\temp.txt'));
//Извлекаем имя файла без расширения. Результат будет 'temp'.
Writeln(TPath.GetFileNameWithoutExtension('C:\MyApp\Temp\temp.txt'));
//Получаем абсолютный путь из относительного. Результат будет 'C:\MyApp\Temp\temp.txt'.
Writeln(TPath.GetFullPath('\MyApp\Temp\temp.txt'));
//Получаем корень для указанного пути. Результат будет 'C:\'.
Writeln(TPath.GetPathRoot('C:\MyApp\Temp\temp.txt'));
//Проверяем, есть ли у имени файла расширение. Результат будет TRUE.
Writeln(TPath.HasExtension('C:\MyApp\Temp\temp.txt'));
//Проверяем, все ли символы в имени файла разрешены.
//Результат будет TRUE.
Writeln(TPath.HasValidFileNameChars('temp.txt', false));
//Результат будет FALSE.
Writeln(TPath.HasValidFileNameChars('t?emp*.txt', false));
//Проверяем, все ли символы в шаблоне имени файла разрешены. Результат будет TRUE.
Writeln(TPath.HasValidFileNameChars('t?emp*.txt', true));
//Проверяем, все ли символы в пути разрешены.
//Результат будет TRUE.
Writeln(TPath.HasValidPathChars('C:\MyApp\Temp\temp.txt', false));
//Результат будет FALSE.
Writeln(TPath.HasValidPathChars('C:\MyApp\<Temp>\temp.txt', false));
//Проверяем, является ли путь абсолютным и начинается ли он с имени диска.
//Результат будет TRUE.
Writeln(TPath.IsDriveRooted('C:\MyApp\Temp\temp.txt'));
//Результат будет FALSE.
Writeln(TPath.IsDriveRooted('\MyApp\Temp\temp.txt'));
//Результат будет FALSE.
Writeln(TPath.IsDriveRooted('\\my_computer\MyApp\Temp\temp.txt'));
//Проверяем, содержит ли путь расширенный префикс.
//Результат будет FALSE.
Writeln(TPath.IsExtendedPrefixed('C:\MyApp\Temp\temp.txt'));
//Результат будет TRUE.
Writeln(TPath.IsExtendedPrefixed('\\?\C:\MyApp\Temp\temp.txt'));
//Проверяем, является ли путь абсолютным.
//Результат будет TRUE.
Writeln(TPath.IsPathRooted('C:\MyApp\Temp\temp.txt'));
//Результат будет TRUE.
Writeln(TPath.IsPathRooted('\MyApp\Temp\temp.txt'));
//Результат будет FALSE.
Writeln(TPath.IsPathRooted('..\MyApp\Temp\temp.txt'));
//Результат будет TRUE.
Writeln(TPath.IsPathRooted('\\my_computer\MyApp\Temp\temp.txt'));
//Проверяем, является ли путь относительным.
//Результат будет FALSE.
Writeln(TPath.IsRelativePath('C:\MyApp\Temp\temp.txt'));
//Результат будет FALSE.
Writeln(TPath.IsRelativePath('\MyApp\Temp\temp.txt'));
//Результат будет TRUE.
Writeln(TPath.IsRelativePath('..\MyApp\Temp\temp.txt'));
//Результат будет FALSE.
Writeln(TPath.IsRelativePath('\\my_computer\MyApp\Temp\temp.txt'));
//Проверяем, указан ли путь в UNC формате.
//Результат будет TRUE.
Writeln(TPath.IsUNCPath('\\?\UNC\my_computer\shared_folder'));
//Проверяем, указан ли корень в пути в формате UNC.
//Результат будет TRUE.
Writeln(TPath.IsUNCRooted('\\?\UNC\my_computer\shared_folder'));
//Проверяем соответствие имени файла шаблону.
//Результат будет TRUE.
Writeln(TPath.MatchesPattern('Temp.txt', '*.txt', false));
//Результат будет TRUE.
Writeln(TPath.MatchesPattern('Temp.txt', 't???.txt', false));
//Результат будет FALSE.
Writeln(TPath.MatchesPattern('Temp.txt', '*.dat', false));
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Часто в программе нужно создавать временные файлы, для которых нужно придумывать уникальные имена. Чтобы не придумывать свой собственный алгоритм для формирования уникального имени файла вы можете использовать следующие функции структуры TPath: GetTempFileName, GetGUIDFileName или GetRandomFileName. Первая функция создаёт пустой временный файл в папке операционной системы для хранения временных файлов, (см. функцию TPath.GetTempPath) и возвращает абсолютное имя созданного файла. Остальные две функции только генерируют имя файла и не гарантируют его уникальность.
Вот примеры использования функций:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils;
var
fileName: string;
begin
try
//Создаём пустой временный файл в папке для временных файлов операционной системы.
fileName := TPath.GetTempFileName;
//Имя файла всё время будет разным, например, 'c:\temp\tmp74D0.tmp'.
Writeln(fileName);
//Удаляем созданный временный файл.
TFile.Delete(fileName);
//Создаём GUID, который можно использовать в качестве имени файла.
fileName := TPath.GetGUIDFileName(false);
//Результат всё время будет разный, например, 'F45F5BC9F72A454D8DCF205206A0E0C2'.
Writeln(fileName);
//Чтобы получить из GUID настоящее имя для файла, добавляем путь и расширение.
fileName := TPath.Combine(TPath.GetTempPath, fileName + '.txt');
//Теперь результат будет 'c:\temp\62AD3AB101964F7BBB0216694840F8C4.txt'.
Writeln(fileName);
//Создаём имя для временного файла.
fileName := TPath.GetRandomFileName;
//Результат всё время будет разный, например, 'eJA6Q5HG.0Qs'.
Writeln(fileName);
//Добавляем путь.
fileName := TPath.Combine(TPath.GetTempPath, fileName);
//Теперь результат будет 'c:\temp\eJA6Q5HG.0Qs'.
Writeln(fileName);
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
В функции TPath есть функция DriveExists позволяющая определить, есть на компьютере диск, указанный в пути. Вот пример её использования:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils;
begin
try
//Проверяем, есть ли на компьютере диск, указанный в пути, т.е. диск C:.
//Результат будет TRUE.
Writeln(TPath.DriveExists('C:\Temp1'));
//Результат будет TRUE.
Writeln(TPath.DriveExists('C:'));
//Результат будет FALSE.
Writeln(TPath.DriveExists('Z:\Temp1'));
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Кроме всего вышеперечисленного у структуры TPath есть функции IsValidPathChar и IsValidFileNameChar для проверки символов, подходят ли они для использования в пути и в имени файла и функции GetInvalidFileNameChars и GetInvalidPathChars, которые возвращают символы, которые не допускается использовать в имени файла и в пути. Имея эти символы, вы самостоятельно сможете создать функции, которые будут проверять имена файлов и пути. Посмотрим, что возвращают эти функции:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, IOUtils;
var
c: char;
begin
try
//Проверяем, можно ли использовать символы в пути.
//Результат будет TRUE.
Writeln(TPath.IsValidPathChar('a'));
//Результат будет TRUE.
Writeln(TPath.IsValidPathChar('\'));
//Результат будет FALSE.
Writeln(TPath.IsValidPathChar('<'));
//Проверяем, можно ли использовать символы в имени файла.
//Результат будет TRUE.
Writeln(TPath.IsValidFileNameChar('a'));
//Результат будет FALSE.
Writeln(TPath.IsValidFileNameChar('\'));
//Результат будет FALSE.
Writeln(TPath.IsValidFileNameChar('<'));
//Выдаём символы, которые нельзя использовать в имени файла.
//В результате будет примерно так (не все символы могут быть отображены в консоли):
//☺☻♥♦♣♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼"*/:<>?\|
for c in TPath.GetInvalidFileNameChars do
Write(c);
Writeln;
//Выдаём коды символов, которые нельзя использовать в имени файла.
//В результате будет:
//0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,34,42,47,58,60,62,63,92,124,
for c in TPath.GetInvalidFileNameChars do
begin
Write(integer(c));
Write(',');
end;
Writeln;
//Выдаём символы, которые нельзя использовать в пути.
//В результате будет примерно так (не все символы могут быть отображены в консоли):
//☺☻♥♦♣♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼"<>|
for c in TPath.GetInvalidPathChars do
Write(c);
Writeln;
//Выдаём коды символов, которые нельзя использовать в пути.
//В результате будет:
//0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,34,60,62,124,
for c in TPath.GetInvalidPathChars do
begin
Write(integer(c));
Write(',');
end;
Writeln;
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
И в завершении вкратце упомяну ещё методы GetAttributes и SetAttributes у структуры TPath. Они умеют читать и устанавливать атрибуты файлов и директорий. Описывать их нет смысла, т.к. они по своим функциям повторяют одноимённые методы структур TFile и TDirectory.
Заключение
Как видите, набор инструментов в юните System.IOUtils очень большой. Поверьте, при работе с файлами он существенно облегчает работу. Надеюсь, что статья понравится не только тем, кто ещё не был знаком с замечательным юнитом System.IOUtils, но и тем, кто уже его использует. Ведь и в том, что, казалось бы, уже хорошо знакомо, часто можно найти что-то новое и неизученное.
Комментарии
На самом деле всё просто, IOUtils адаптирован под все платформы поддерживаемые Embarcadero на данный момент (Windows, Android, iOS, OSx). Т.е. использование описанных выше классов, в любой операционке приведет к корректному выполнению операций файлового ввода - вывода. Что согласитесь, задача весьма не тривиальная.
Но
Цитата: Почему-то не выдаёт результатов если папка называется "Новая (1)" а в seachbox-e написано "новая", то есть присутствует чувствительность к регистру букв (латинских это не касается).
1. Узнать размер тома в Мб
2. Подсчитать количество файлов в директории
Если бы тысячи программеров не писали эти свои велосипеды - и IOUtils бы никогда не появилось
RSS лента комментариев этой записи