FilePos — Функция Delphi

Содержание

FilePos — Функция Delphi

На этом шаге мы рассмотрим процедуры и функции, предназначенные для работы с файловым указателем.

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

1. Установка указателя. Процедура Seek предназначена для изменения положения указателя файла. Ее общий вид:

Номер позиции указывает номер элемента, на который нужно разместить указатель файла. Если номер позиции равен 0, то указатель располагается в начале файла (на первом элементе).

2. Определение количества элементов в файле. Функция FileSize предназначена для подсчёта элементов файла. Общий вид:

Результатом работы функции будет величина типа Integer , значение которой равно количеству элементов в файле.

3. Определение номера элемента. Функция FilePos возвращает номер элемента, на который показывает указатель файла (номер текущего элемента). Её общий вид:

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

Дополните программу проверкой введенного числа Nomer . Оно должно принадлежать промежутку от 1 до количества элементов файла.
Решение и комментарии вы можете посмотреть здесь.

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

Она принимает истинное значение ( True ), если достигнут конец файла, и ложное ( False ) — в противном случае. Напомним, что при достижении конца файла указатель располагается за последним элементом файла (рис.1):

Рис.1. Положение указателя в случае истинности функции Eof

Изменим предыдущую программу, использовав рассмотренную функцию:

Использованное в заголовке цикла условие обрабатывается следующим образом: сначала анализируется значение функции Eof(K) . Эта функция возвращает значение «ложь», так как указатель расположен не в конце файла. Отрицание ( Not ) лжи есть истина. Поэтому проверяемое условие является истинным и, следовательно, выполняется тело цикла. Первый оператор в теле цикла — это конструкция Readln(k,a); , при выполнении которой элемент, на который показывает указатель, помещается в переменную a , и указатель перемещается на следующую позицию. Так продолжается до тех пор, пока указатель не переместится за последний элемент. В этом случае значение функции Eof(K) есть «истина», а отрицание истины — «ложь». Таким образом, проверяемое условие становится ложным, тело цикла не выполняется и осуществляется переход к оператору, расположенному после тела цикла. Это конструкция Close(K); .

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

Функции, процедуры файлового ввода и вывода в Дельфи

Append (Var F:Text) – открывает текстовый файл, связанный с переменной F, для добавления его в конец.

CloseFile (var F) – закрывает открытый файл, связанный с файловой переменной F.

AssignFile (var F; FileName: String) – связывает имя внешнего файла FileName с файловой переменной F.

BlockRead / BlockWrite (var F:file; var Buf; Count: Integer[; var Result: Integer]) – читает Count записей из нетипизированного файла, связанного с файловой переменной F, в буфер Buf. Если задан параметр Result, то в него возврашается число действительно прочитанных записей. BlockWrite соответственно записывает Count записей из буфера Buf в файл.

Eof (var F):Boolean – возвращает true при достижении конца файла.

Eoln (var F:Text):Boolean – возвращает признак конца строки в текстовом файле.

Eraise (var F) – удаление внешнего файла связанного с переменной F.

FileSize (var F):Integer – текущий размер файла, связанного с переменной F. Не используется для текстовых файлов.

Flush (var F:Text) – очистка буфера выходного текстового файла, связанного с переменной F.

FilePos (var F): LongInt – возвращает текущую позицию типизированного или нетипизированного файла, связанного с переменной F. Позиция, соответствующая началу файла – 0.

IOResult: Integer – возвращает целое значение, характеризующее выполнение последней операции ввода или вывода.

Read (F, ) – читает из файла, связанного с переменной F, одно или более значений в одну или более переменную.

ReadLn (F, ) – читает одно или более значений в одну или более переменную и переходит на начало новой строки текстового файла.

Rename (var F: File; NewName:String) – переименование файла. В NewName указан полный путь к переименованному файлу.

Reset (var F[: File; RecSize: Word]) – открывает существующий файл связанный с файловой переменной F. RecSize задается для нетипизированных файлов и устанавливает длину записи в байтах (по умолчанию 128).

ReWrite (var F[: File; RecSize: Word]) – создает и открывает новый файл, связанный с файловой переменной F. RecSize задается для нетипизированных файлов и устанавливает длину записи в байтах (по умолчанию 128).

Seek (var F; N:LongInt) – перемещает текущую позицию в позицию N. Для текстовых файлов не используется.

SeekEof (var F:Text): Boolean – возвращает true при достижении конца текстового файла, связанного с файловой переменной F.

SeekEoln (var F:Text): Boolean – возвращает true при достижении конца строки текстового файла, связанного с файловой переменной F.

Truncate (var F) – усекает типизированный или нетипизированный файл, связанный файловой переменной F, на текущей позиции.

Write (var F; ) – записывает значение(я) в файл, связанный файловой переменной F.

WriteLn (var F; ) – записывает значение(я) в файл, затем заносит маркер конца строки в текстовый файл, связанный файловой переменной F.

. Программирование файлового ввода Delphi функции файлового ввод вывод в с++

Проблемма с BlockRead

03.12.2012, 20:31

BlockWrite и BlockRead
http://www.delphibasics.ru/BlockWrite.php var myFile : File; byteArray : array of byte; .

Blockread file
Здравствуйте!Выбираю фаел через opendialog,скажите как потом считать выбранный фаел в переменную?

Альтернатива AssignFile, BlockRead, BlockWrite
Доброго времени суток. Появилась такая проблема. AssignFile не умеет хавать большие файлы, а мне.

Зацикливание при использовании Blockread
Хочу перезаписать содержимое одного файла в другой. И если открыть картинку или текстовый файл.

Запись/чтение из бинарного файла. BlockRead
Впервые использую BlockRead и BlockWrite, видимо что то не правильно понял. Запись: i : Word; .

Файловые функции DELPHI. Файловые операции средствами ShellApi.

В Delphi существует понятие — подпрограммы управления файлами ( category File management routines). Процедуры и функции входящие в эту категорию находятся в модулях System, SysUtils (каталог Source\Rtl\Sys) и FileCtrl (каталог Source\Vcl). Модуль FileCtrl содержит только две функции из категории подпрограмм управления файлами — это DirectoryExists и ForceDirectories. Местонахождение остальных процедур и функций определяется следующим образом. Если в подпрограмме используется файловая переменная, то она входит в модуль System. Если дескриптор или имя файла в виде строки, то в модуль SysUtils. Правда есть исключения (интуитивно понятные) ChDir входит в System. Также в System входят MkDir, RmDir из категории ввода/вывода ( I/O routines). Надо отметить, что все подпрограммы, отнесенные к категориям ввода/вывода и текстовых файлов ( Text file routines) находятся в модуле System (исключая процедуру AssignPrn входящую в модуль Printers каталог Source\Vcl). Вот список подпрограмм отсортирован по категориям и по алфавиту.

File management routines — подпрограммы управления файлами

S ystem procedure AssignFile(var F; FileName: string); Связывает файловую переменную с именем файла
System procedure ChDir(S: string); Изменяет текущий каталог
System procedure CloseFile(var F); Закрывает файл по файловой переменной
SysUtils function CreateDir(const Dir: string): Boolean; Создает новый каталог
SysUtils function DeleteFile(const FileName: string): Boolean; Удаляет файл
FileCtrl function DirectoryExists(Name: string): Boolean; Проверяет наличие каталога
SysUtils function DiskFree(Drive: Byte): Int64; Определяет свободное пространство на диске
SysUtils function DiskSize(Drive: Byte): Int64; Определяет полный размер диска
SysUtils function FileAge(const FileName: string): Integer; Определяет время последнего обновления
SysUtils procedure FileClose(Handle: Integer); Закрывает файл по дескриптору
SysUtils function FileDateToDateTime(FileDate: Integer): TDateTime; Преобразует DOS-дату в Delphi-дату
SysUtils function FileExists(const FileName: string): Boolean; Проверяет наличие файла
SysUtils function FileGetAttr(const FileName: string): Integer; Определяет атрибуты файла
SysUtils function FileGetDate(Handle: Integer): Integer; Определяет время последнего обновления
SysUtils function FileOpen(const FileName: string; Mode: LongWord): Integer; Открывает существующий файл
SysUtils function FileRead(Handle: Integer; var Buffer; Count: Integer): Integer; Читает из файла
SysUtils function FileSearch(const Name, DirList: string): string; Ищет файл в списке каталогов
SysUtils function FileSeek(Handle, Offset, Origin: Integer): Integer; Меняет позицию указателя
SysUtils function FileSetAttr(const FileName: string; Attr: Integer): Integer; Устанавливает атрибуты файла
SysUtils function FileSetDate(Handle: Integer; Age: Integer): Integer; Устанавливает время последнего обновления
SysUtils function FileWrite(Handle: Integer; const Buffer; Count: Integer): Integer; Записывает в файл
SysUtils procedure FindClose(var F: TSearchRec); Прекращает поиск файлов
SysUtils function FindFirst(const Path: string; Attr: Integer; var F: TSearchRec): Integer; Начинает поиск файлов
SysUtils function FindNext(var F: TSearchRec): Integer; Продолжает поиск файлов
FileCtrl function ForceDirectories(Dir: string): Boolean; Создает все каталоги пути
SysUtils function GetCurrentDir: string; Определяет текущий каталог
System procedure GetDir(D: Byte; var S: string); Определяет текущий каталог
SysUtils function RemoveDir(const Dir: string): Boolean; Удаляет каталог
SysUtils function RenameFile(const OldName, NewName: string): Boolean; Переименовывает файл
SysUtils function SetCurrentDir(const Dir: string): Boolean; Устанавливает текущий каталог

I/O routines — подпрограммы ввода/вывода

Модуль Подпрограмма
System procedure Append(var F: Text); Добавляет текст в конец файла
System procedure BlockRead(var F: File; var Buf; Count: Integer [; var AmtTransferred: Integer]); Читает блок из файла
System procedure BlockWrite(var f: File; var Buf; Count: Integer [; var AmtTransferred: Integer]); Записывает блок в файл
System function Eof(var F): Boolean; Определяет конец файла
System function FilePos(var F): Longint; Определяет позицию указателя
System function FileSize(var F): Integer; Определяет размер файла
System function IOResult: Integer; Определяет ошибки предыдущего ввода/вывода
System procedure MkDir(S: string); Создает каталог
System procedure Rename(var F; Newname:string); Переименовывает файл
System procedure Reset(var F [: File; RecSize: Word ] ); Открывает файл
System procedure Rewrite(var F: File [; Recsize: Word ] ); Создает и открывает новый файл
System procedure RmDir(S: string); Удаляет каталог
System procedure Seek(var F; N: Longint); Устанавливает позицию указателя
System procedure Truncate(var F); Усекает файл до текущей позиции указателя

Text file routines — подпрограммы текстовых файлов

Модуль Подпрограмма
Printers procedure AssignPrn(var F: Text); Связывает файловую переменную с принтером
System function Eoln [(var F: Text) ]: Boolean; Определяет конец строки
System procedure Erase(var F); Удаляет файл
System procedure Flush(var F: Text); Переписывает данные в файл из его буфера
System procedure Read(F , V1 [, V2. Vn ] ); Читает из файла
System procedure Readln([ var F: Text; ] V1 [, V2, . Vn ]); Читает из файла до конца строки
System function SeekEof [ (var F: Text) ]: Boolean; Определяет конец файла
System function SeekEoln [ (var F: Text) ]: Boolean; Определяет конец строки
System procedure SetTextBuf(var F: Text; var Buf [ ; Size: Integer] ); Устанавливает новый буфер
System procedure Write(F, V1 [, V2. Vn ] ); Записывает в файл
System procedure Writeln([ var F: Text; ] V1 [, V2, . Vn ] ); Записывает в файл с концом строки

Проверяем наличие файла и записываем его
type
TFileData=record
Name:String[10];
ExtDat:Extended;
end;
var
Cals: File of TFileData;
CalsData: TFileData;

procedure NAME;
//Описание процедуры
var p: Real;
u: Byte;
begin
Road:=’<файл>.dat’;
Dest:=’<каталог>‘+Road;
try
AssignFile(Cals,Dest);
// Если файл существует открываем на чтение, иначе создаем новый
If FileExists(Cals) then Reset(cals) else Rewrite(cals);
// установим позицию чтения в конец файла
seek (cals,filesize(cals));
CalsData.Name := ‘название параметра’;
CalsData.ExtDat := <сами данные>;
Write(Cals,CalsData);
except
on E: EInOutError do
ShowMessage(‘При выполнении файловой операции возникла ошибка’+
‘ № ‘+ IntToStr(E. ErrorCode)+’: ‘+SysErrorMessage(GetLastError));
on E: EAccessViolation do
ShowMessage(‘Ошибка!: ‘+SysErrorMessage(GetLastError));
end;
CloseFile(cals); //Независимо от того что произошло выше закрываем открытый файл
end;

Перепишем файл a.dat в файл b.dat, удалив признаки конца файла:

Proedure MyWrite;
var
f1,f2 :file of Byte;
a :Byte;
i :Longint;
begin
<$I->
AssignFile(f1, ‘a.dat’);
AssignFile(f2, ‘b.dat’);
Reset(f1);
Rewrite(f2);
for i := 1 to FileSize(f1) do
begin
Read(f1, a);
if a <> 26 then Write(f2, a);
end;
CloseFile(f1);
CloseFile(f2);
end.

Файл записей. Пишем и читаем любую:

Procedure MyBook;
type TR=Record
Name:string[100];
Age:Byte;
Income:Real;
end;
var f:file of TR;
r:TR;
begin
//assign file
assignFile(f, ‘MyFileName’);
//open file
if FileExists(‘MyFileName’) then
reset(f)
else
rewrite(f);
//чтение 10й записи
seek(f,10);
read(f,r);
//запись 20й записи
seek(f, 20);
write(f,r);
closefile(f);
end;

Файловые операции средствами ShellAPI.


Автор: Владимир Татарчевский

Рассмотрим применение функции SHFileOperation.
function SHFileOperation(const lpFileOp: TSHFileOpStruct): Integer; stdcall;
Функция позволяет производить копирование, перемещение, переименование и удаление (в том числе и в Recycle Bin) объектов файловой системы.
Функция возвращает 0, если операция выполнена успешно, и ненулевое значение в противном случае.

Функция имеет единственный аргумент — структуру типа TSHFileOpStruct, в которой и передаются все необходимые данные. Эта структура выглядит следующим образом:

_SHFILEOPSTRUCTA = packed record
Wnd: HWND;
wFunc: UINT;
pFrom: PAnsiChar;
pTo: PAnsiChar;
fFlags: FILEOP_FLAGS;
fAnyOperationsAborted: BOOL;
hNameMappings: Pointer;
lpszProgressTitle: PAnsiChar; < используется только при установленном флаге FOF_SIMPLEPROGRESS >
end;

Поля структуры имеют следующее назначение:
hwnd Хэндл окна, на которое будут выводиться диалоговые окна о ходе операции.
wFunc Требуемая операция. Может принимать одно из значений:

FO_COPY Копирует файлы, указанные в pFrom в папку, указанную в pTo.
FO_DELETE Удаляет файлы, указанные pFrom (pTo игнорируется).
FO_MOVE Перемещает файлы, указанные в pFrom в папку, указанную в pTo.
FO_RENAME Переименовывает файлы, указанные в pFrom.
pFrom — указатель на буфер, содержащий пути к одному или нескольким файлам. Если файлов несколько, между путями ставится нулевой байт. Список должен
заканчиваться двумя нулевыми байтами.

pTo — аналогично pFrom, но содержит путь к директории — адресату, в которую производится копирование или перемещение файлов. Также может
содержать несколько путей. При этом нужно установить флаг FOF_MULTIDESTFILES.

fFlags — управляющие флаги.
FOF_ALLOWUNDO Если возможно, сохраняет информацию для возможности UnDo.
FOF_CONFIRMMOUSE Не реализовано.
FOF_FILESONLY Если в поле pFrom установлено *.*, то операция будет производиться только с файлами.
FOF_MULTIDESTFILES Указывает, что для каждого исходного файла в поле pFrom указана своя директория — адресат.
FOF_NOCONFIRMATION Отвечает «yes to all» на все запросы в ходе опеации.
FOF_NOCONFIRMMKDIR Не подтверждает создание нового каталога, если операция требует, чтобы он был создан.
FOF_RENAMEONCOLLISION В случае, если уже существует файл с данным именем, создается файл с именем «Copy #N of. »
FOF_SILENT Не показывать диалог с индикатором прогресса.
FOF_SIMPLEPROGRESS Показывать диалог с индикатором прогресса, но не показывать имен файлов.
FOF_WANTMAPPINGHANDLE Вносит hNameMappings элемент. Дескриптор должен быть освобожден функцией SHFreeNameMappings.
fAnyOperationsAborted
Принимает значение TRUE если пользователь прервал любую файловую операцию до ее завершения и FALSE в ином случае.

hNameMappings — дескриптор объекта отображения имени файла, который содержит массив структур SHNAMEMAPPING. Каждая структура содержит старые и новые имена пути для каждого файла, который перемещался, был скопирован, или переименован. Этот элемент используется только, если установлен флаг FOF_WANTMAPPINGHANDLE.

lpszProgressTitle — указатель на строку, используемую как заголовок для диалогового окна прогресса. Этот элемент используется только, если установлен флаг FOF_SIMPLEPROGRESS.

Примечание. Если pFrom или pTo не указаны, берутся файлы из текущей директории. Текущую директорию можно установить с помощью функции
SetCurrentDirectory и получить функцией GetCurrentDirectory.

Добавьте в секцию uses модуль ShellAPI, в котором определена функция SHFileOperation.

procedure TForm1.Button1Click(Sender: TObject);
var
SHFileOpStruct : TSHFileOpStruct;
From : array [0..255] of Char;
begin
SetCurrentDirectory( PChar( ‘C:\’ ) );
From := ‘Test1.tst’ + #0 + ‘Test2.tst’ + #0 + #0;
with SHFileOpStruct do
begin
Wnd := Handle;
wFunc := FO_DELETE;
pFrom := @From;
pTo := nil;
fFlags := 0;
fAnyOperationsAborted := False;
hNameMappings := nil;
lpszProgressTitle := nil;
end;
SHFileOperation( SHFileOpStruct );
end;

Ни один из флагов не установлен. Если вы хотите не просто удалить файлы, а переместить их в корзину, должен быть
установлен флаг FOF_ALLOWUNDO.

Напишем функцию, создающую из массива строк буфер для передачи его в качестве параметра pFrom. После
каждой строки в буфер вставляется нулевой байт, в конце списка — два нулевых байта.
type TBuffer = array of Char;

procedure CreateBuffer( Names : array of string; var P : TBuffer );
var I, J, L : Integer;
begin
for I := Low( Names ) to High( Names ) do
begin
L := Length( P );
SetLength( P, L + Length( Names[ I ] ) + 1 );
for J := 0 to Length( Names[ I ] ) — 1 do
P[ L + J ] := Names[ I, J + 1 ];
P[ L + J ] := #0;
end;
SetLength( P, Length( P ) + 1 );
P[ Length( P ) ] := #0;
end;

Функция, удаляющая файлы, переданные ей в списке Names. Параметр ToRecycle определяет, будут ли файлы перемещены в корзину или удалены. Функция возвращает 0, если операция выполнена успешно, и ненулевое значение, если функции переданы имена несуществующих файлов.
function DeleteFiles( Handle : HWnd; Names : array of string; ToRecycle : Boolean ) : Integer;
var
SHFileOpStruct : TSHFileOpStruct;
Src : TBuffer;
begin
CreateBuffer( Names, Src );
with SHFileOpStruct do
begin
Wnd := Handle;
wFunc := FO_DELETE;
pFrom := Pointer( Src );
pTo := nil;
fFlags := 0;
if ToRecycle then fFlags := FOF_ALLOWUNDO;
fAnyOperationsAborted := False;
hNameMappings := nil;
lpszProgressTitle := nil;
end;
Result := SHFileOperation( SHFileOpStruct );
Src := nil;
end;

Освобождаем буфер Src простым присваиванием значения nil. Потери памяти при этом не происходит, происходит корректное уничтожение динамического массива.

Проверяем :
procedure TForm1.Button1Click(Sender: TObject);
begin
DeleteFiles( Handle, [ ‘C:\Test1’, ‘C:\Test2’ ], True );
end;

Файлы ‘Test1’ и ‘Test2’ удаляются совсем, без помещения в корзину, несмотря на установленный флаг FOF_ALLOWUNDO. При использовании функции SHFileOperation используйте полные пути, когда это возможно.

Копирование и перемещение.

Функция перемещает файлы указанные в списке Src в директорию Dest. Параметр Move определяет, будут ли файлы перемещаться или копироваться. Параметр AutoRename указывает, переименовывать ли файлы в случае конфликта имен.
function CopyFiles( Handle : Hwnd; Src : array of string; Dest : string; Move : Boolean; AutoRename : Boolean ) : Integer;
var
SHFileOpStruct : TSHFileOpStruct;
SrcBuf : TBuffer;
begin
CreateBuffer( Src, SrcBuf );
with SHFileOpStruct do
begin
Wnd := Handle;
wFunc := FO_COPY;
if Move then wFunc := FO_MOVE;
pFrom := Pointer( SrcBuf );
pTo := PChar( Dest );
fFlags := 0;
if AutoRename then fFlags := FOF_RENAMEONCOLLISION;
fAnyOperationsAborted := False;
hNameMappings := nil;
lpszProgressTitle := nil;
end;
Result := SHFileOperation( SHFileOpStruct );
SrcBuf := nil;
end;

Выполнение:
procedure TForm1.Button1Click(Sender: TObject);
begin
CopyFiles( Handle, [ ‘C:\Test1’, ‘C:\Test2’ ], ‘C:\Temp’, True, True );
end;

Переименование.
function RenameFiles( Handle : HWnd; Src : string; New : string; AutoRename : Boolean ) : Integer;
var SHFileOpStruct : TSHFileOpStruct;
begin
with SHFileOpStruct do
begin
Wnd := Handle;
wFunc := FO_RENAME;
pFrom := PChar( Src );
pTo := PChar( New );
fFlags := 0;
if AutoRename then fFlags := FOF_RENAMEONCOLLISION;
fAnyOperationsAborted := False;
hNameMappings := nil;
lpszProgressTitle := nil;
end;
Result := SHFileOperation( SHFileOpStruct );
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
RenameFiles( Handle, ‘C:\Test1’ , ‘C:\Test3’ , False );
end;

Процедуры и функции для работы с файлами в Delphi

Читайте также:

  1. Cущность банковского процента, его функции и роль.
  2. I. Функции времени в спутниковых технологиях.
  3. I. Экстремумы функции двух переменных
  4. II. Основные направления социально-медицинской работы с семьями детей ограниченными возможностями
  5. III. Лекционный материал по теме: ПРАВИЛА РАБОТЫ НА ЛЕКЦИИ
  6. IV. Функции
  7. IX. Лекционный материал: ОРГАНИЗАЦИЯ САМОСТОЯТЕЛЬНОЙ РАБОТЫ
  8. N В условиях интенсивной мышечной работы, при гипоксии (например, интенсивный бег на 200м в течении 30 с) распад углеводов временно протекает в анаэробных условиях
  9. N Выполняет функции гормона
  10. N Особенности структуры и функции обуславливают особенности в метаболизме клеток
  11. TCR. Функции Т-лимфоцитов
  12. VIII. Принципы работы вычислительной системы

Основные процедуры и функции:

Процедура: AssignFile(var Vf; FileName: string);Модуль: System

Описание: Процедура устанавливает ассоциативную связь между файловой переменной Vf и внешним файлом, имя которого определено параметром FileName. Все операции, производимые с файловой переменной, будут производиться со связанным с ней файлом. FileName — выражение типа string или PChar (если допускается расширенный синтаксис). Если в качестве имени файла указать пустую строку, то файловая переменная будет ассоциирована со стандартным файлом ввода (когда после AssignFile следует процедура Reset) или вывода (когда после следует процедура Rewrite).

Пример:
var Vf : file of Integer;
begin
.
AssignFile(Vf,'work.dat'); //инициализирует файловую переменную
Rewrite(Vf); //создает файл 'work.dat'
CloseFile(Vf); //закрывает файл
.
end;

Процедура: BlockRead(var Vf: file; var Buf; Count: Integer [;var AmtTransferred: Integer]); Модуль: System

Описание: Процедура читает одну или большее количество записей из открытого файла, связанного с файловой переменной Vf, в переменную Buf. Параметр Count определяет количество записей, которое необходимо прочитать из файла. В параметре AmtTransferred возвращается фактическое количество прочитанных записей, которое может быть меньше Count (например, когда размер последнего блока данных в файле меньше заданного размера записи). Максимальный размер прочитанного блока равен Count*RecSize байт. RecSize — размер записи, определенный, во время открытия файла (если размер записи не был задан, то используется значение по умолчанию — 128 байт). Параметр AmtTransferred является необязательным. Но если данный параметр опущен, а количество прочитанных записей меньше Count, то возникнет ошибка ввода/вывода (исключение EInOutError).

Пример:
var
Vf1, Vf2: file; NRead, NWrite: Integer;
Buf: array[1..1024] of Char;
begin
AssignFile(Vf1, 'read.txt');
Reset(Vf1, 1); //Устан-ет размер записи входного файла = 1
AssignFile(Vf2, 'write.txt');
Rewrite(Vf2, 1); //Устан-ет размер записи выходного файла = 1
repeat
BlockRead(Vf1, Buf, SizeOf(Buf), NRead); //читает данные
BlockWrite(Vf2, Buf, NRead, NWrite); //записывает данные
until (NRead = 0) or (NWrite <> NRead);
CloseFile(Vf1);
CloseFile(Vf2);
end;

Процедура: BlockWrite(var Vf: file; var Buf, Count: Integer [;var AmtTransferred: Integer]); Модуль: System

Описание: Процедура записывает одну или несколько записей из переменной Buf во внешний файл, связанный с файловой переменной Vf. Параметр Count определяет количество записей, которое необходимо записать в файл. В параметре AmtTransferred возвращается фактическое количество скопированных записей, которое может быть меньше Count (например, когда место на диске закончилось до окончания записи в файл). Максимальный размер записываемого блока равен Count*RecSize байт, где RecSize — размер записи, определенный, во время открытия файла или 128 байт, если размер записи не был определен. Параметр AmtTransferred является необязательным. Но если данный параметр опущен, и количество прочитанных записей будет меньше Count, то возникнет ошибка ввода/вывода (исключение EinOutError).

Пример:
var
Vf1, Vf2: file;
NRead, NWrite: Integer;
Buf: array[1..1024] of Char;
begin
AssignFile(Vf1, 'read.txt');
Reset(Vf1, 1); //Устан-ет размер записи входного файла = 1
AssignFile(Vf2, 'write.txt');
Rewrite(Vf2, 1); //Устан-ет размер записи выходного файла = 1
repeat
BlockRead(Vf1, Buf, SizeOf(Buf), NRead); //читает данные
BlockWrite(Vf2, Buf, NRead, NWrite); //записывает данные
until (NRead = 0) or (NWrite <> NRead);
CloseFile(Vf1);
CloseFile(Vf2);
end;

Процедура: CloseFile(var Vf); Модуль: System

Описание: Процедура разрывает ассоциативную связь между файловой переменной и внешним файлом, при этом, файл обновляется и закрывается. Механизм обработки ошибок ввода/вывода с помощью обработчиков исключений включается директивой компилятора <$I+>. При использовании директивы <$I->информацию об ошибках можно получить с помощью функции IOResult.

Пример:
var
Vf: file of Integer;
begin
.
AssignFile(Vf, 'work.dat'); //инициализирует файловую переменную
Rewrite(Vf); //создает файл 'work.dat'
CloseFile(Vf); //закрывает файл
.
end;

Процедура: Erase(Var Vf); Модуль: System

Описание: Удаляет файл, связанный с файловой переменной Vf. Vf — файловая переменная, ассоциированная с файлом любого типа. Перед удалением файл необходимо закрыть процедурой CloseFile.

Пример:
var
Vf: file;
begin
AssignFile(Vf, 'C:\WINDOWS\TEMP\tmpfile.tmp');
Rewrite(Vf); //создает временный файл 'tmpfile.tmp'
.
CloseFile(Vf); //закрывает файл
Erase(Vf); //удаляет файл
end;

Процедура: FindClose(var F: TSearchRec); Модуль: SysUtils

Описание: Процедура завершает последовательность вызовов функций FindFirst — FindNext и высвобождает память, выделенную при вызове функции FindFirst.

Процедура: Read(Vf, V1 [, V2, . Vn ]); Модуль: System

Описание: Процедура читает информацию из файла, ассоциированного с файловой переменной Vf, в переменную(ые) Vn.

Типизированные файлы. Читает запись (компонент) из файла в переменную. Файлы строкового типа. Читает все символы до маркера конца строки, не включая его или пока значение Eof(Vf) не будет равно True. Если размер прочитанной строки больше, чем размер строковой переменной, то строка усекается. После прочтения строки, каждый последующий вызов данной процедуры будет возвращать пустую строку, т.к. процедура Read не переводит указатель на новую строку. Если необходимо прочитать более одной записи из файла, то используйте процедуру ReadLn. Файлы символьного типа. Читает символ из файла. Если достигнут конец файла (т.е. Eof(Vf)=True), то процедура возвращает символ ‘Ctrl+Z’ (ASCII код 26).

Илон Маск рекомендует:  Символ в качестве маркера

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

Пример:
var
Vf1,Vf2: TextFile;
FileName1, FileName2: string;
C: Char;
begin
FileName1:='read.txt'; //подразумевается, что файл существует
FileName2:='write.txt';
AssignFile(Vf1, FileName1);
Reset(Vf1); //открывает файл 'read.txt'
AssignFile(Vf2, FileName2);
Rewrite(Vf2); //создает файл 'write.txt'
while not Eof(Vf1) do //повтор, пока не достигнут конец файла
begin
Read(Vf1, C); //читает символ из файла 'read.txt'
Write(Vf2, C); //записывает символ в файл 'write.txt'
end;
CloseFile(Vf2);
CloseFile(Vf1);
end;

Процедура: Rename(var Vf; NewName); Модуль: System

Описание: Процедура переименовывает файл, связанный с файловой переменной Vf. Новое имя файла указывается в параметре NewName. NewName — переменная типа string или PChar (если допускается расширенный синтаксис). После выполнения данной процедуры все операции c файловой переменной Vf будут производиться над переименованным файлом.

Процедура: Reset(var Vf: File [;RecSize: Word]); Модуль: System

Описание: Процедура открывает существующий файл и устанавливает указатель в начало файла. Vf — файловая переменная, ассоциированная с файлом любого типа при помощи процедуры AssignFile. RecSize — необязательный параметр, указывающий размер записи файла. Когда параметр RecSize опущен, размер записи принимается по умолчанию 128 байт. Если файл, связанный с файловой переменной Vf, не существует, то при вызове процедуры Reset возникнет ошибка. Если файл уже открыт, то при вызове данной процедуры он сначала закрывается, а затем снова открывается. Если с файловой переменной Vf связан текстовый файл, то он открывается только для чтения.

Процедура: Rewrite(var Vf: File [; Recsize: Word]); Модуль: System

Описание: Процедура создает новый файл и открывает его. Параметр Vf определяет файловую переменную, связанную с любым типом файлов при помощи процедуры AssignFile. RecSize — необязательный параметр, указывающий размер записи файла. Когда параметр RecSize опущен, размер записи принимается по умолчанию 128 байт. Если файл с заданным именем уже существует, то процедура удаляет старый файл и создает новый пустой файл. Если файл существует и открыт, то функция перед удалением старого файла сначала закрывает его. Если файловая переменная Vf связана с текстовым файлом, то он открывается только для записи. После вызова данной процедуры Eof(Vf)=True.

Процедура: Seek(var Vf; N: Longint); Модуль: System

Описание: Устанавливает файловый указатель в заданную позицию файла. Параметр Vf представляет собой файловую переменную, ассоциированную с типизированным или нетипизированным файлом. Для успешного выполнения процедуры файл должен быть открыт. Индекс позиции, в которую будет установлен указатель, определяется параметром N. Первая позиция в файле имеет индекс 0. Если необходимо добавить данные в конец файла, то поставить указатель в конец файла Vf можно следующим образом: Seek(Vf, FileSize(Vf)).

Процедура: Truncate(var Vf); Модуль: System

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

Процедура: Write(Vf, V1. Vn); (для типизированных файлов) Модуль: System

Описание: Процедура записывает данные в типизированный файл. Параметр Vf представляет собой файловую переменную, связанную с типизированным файлом. Тип переменных V1 . Vn должен соответствовать типу фала. При записи в файл очередного компонента, указатель текущей позиции файла передвигается на следующий компонент. Если перед вызовом данной процедуры указатель стоит в конце файла (Eof(Vf)=True), то записываемые данные будут добавлены в конец файла (размер файла соответственно увеличится).

Функция: DeleteFile(const FileName: string): Boolean; Модуль: SysUtils

Описание: Функция удаляет файл с диска. При успешном выполнении возвращает True, а если файл не существует, или не может быть удален, то — False.

Пример:
var
FileName: string;
begin
.
if DeleteFile(FileName) then
MessageDlg('Файла успешно удален', mtInformation, [mbOk], 0)
else
MessageDlg('Ошибка удаления файла', mtInformation, [mbOk], 0);
.
end;

Функция: DiskFree(Drive: Byte): Int64; Модуль: SysUtils

Описание: Функция возвращает количество свободного места на диске, указанном в параметре Drive, в байтах. Диск определяется следующим образом: 0 — текущий, 1 — ‘A’, 2 — ‘B’, 3 — ‘С’, и т.д. Если указанный диск не существует, или недоступен, то функция возвращает -1.

Функция: DiskSize(Drive: Byte): Int64; Модуль: SysUtils

Описание: Функция возвращает размер диска Drive в байтах. Диск определяется следующим образом: 0 — текущий, 1 — ‘A’, 2 — ‘B’, 3 — ‘С’, и т.д. Если указанный диск не существует, или недоступен, то функция возвращает -1.

Функция: Eof(var Vf ): Boolean; Модуль: System

Описание: Функция определяет, стоит ли указатель текущей позиции в конце файла Vf (Vf — файловая переменная). Если указатель стоит на последнем символе файла, или файл не содержит данных, то функция возвращает True, а иначе — False.

Пример:
var
Vf1,Vf2: TextFile;
FileName1, FileName2: string;
C: Char;
begin
FileName1:='read.txt'; //подразумевается, что файл существует
FileName2:='write.txt';
AssignFile(Vf1, FileName1);
Reset(Vf1); //открывает файл 'read.txt'
AssignFile(Vf2, FileName2);
Rewrite(Vf2); //создает файл 'write.txt'
while not Eof(Vf1) do //повтор, пока не достигнут конец файла
begin
Read(Vf1, C); //читает символ из файла 'read.txt'
Write(Vf2, C); //записывает символ в файл 'write.txt'
end;
CloseFile(Vf2);
CloseFile(Vf1);
end;

Функция: FileExists(const FileName: string): Boolean; Модуль: SysUtils

Описание: Функция проверяет, существует ли файл с именем FileName. Если файл существует, то функция возвращает True, иначе — False.

Функция: FileGetAttr(const FileName: string): Integer; Модуль: SysUtils

Описание: Функция возвращает атрибуты файла, имя которого передано в параметре FileName. Атрибуты могут быть разделены с помощью оператора AND и следующих значений констант атрибутов:

Константа Значение Описание
faReadOnly faHidden faSysFile faVolumeID faDirectory faArchive faAnyFile $00000001 $00000002 $00000004 $00000008 $00000010 $00000020 $00000003F Только чтение Скрытый файл Системный файл Идентификатор тома Каталог Архивный файл Произвольный файл

В случае возникновении ошибки функция возвращает -1.

Функция: FilePos(var Vf): LongInt; Модуль: System

Описание: Функция возвращает текущую позицию указателя в файле (файл должен быть предварительно открыт). Параметр Vf представляет собой файловую переменную, ассоциированную с файлом. Данная функция не может быть применена к текстовым файлам.

Пример:
var
Vf: File of Byte;
S : string;
Size, I: Integer;
begin
Randomize; AssignFile(Vf, 'work.dat');
Rewrite(Vf); //создает файл work.dat
for I:= 0 to 100 do
begin
Seek(Vf, I);
Write(Vf, I); //записывает в файл послед. чисел от 1 до 100
end;
Size:= FileSize(Vf); //определяет размер файла
Seek(Vf, random(Size)); //устанавливает указатель в произвольную позицию
MessageDlg('Позиция указателя: ' + IntToStr(FilePos(Vf)), mtInformation, [mbOk], 0);
.
CloseFile(Vf);
end;

Функция: FileSearch(const FileName, DirList: string): string; Модуль: SysUtils

Описание: Функция осуществляет поиск файла FileName в каталогах, указанных в параметре DirList. Имя файла должно быть представлено в DOS-формате. Список каталогов DirList представляет собой строку, содержащую наименования каталогов, разделенных точками с запятой (например, ‘C:\;C:\WINDOWS; C:\WINDOWS\TEMP’). Если файл найден, то функция возвращает полный путь к файлу, а иначе возвращается пустая строка.

Функция: FileSetAttr(const FileName: string): Integer; Модуль: SysUtils

Описание: Функция устанавливает атрибуты файла, имя которого передано в параметре FileName. Атрибуты перечисляются в параметре Attr с помощью оператора OR. В случае успешного выполнения функция возвращает 0, а иначе возвращается код ошибки Windows.
Значение констант атрибутов:

Константа Значение Описание
faReadOnly faHidden faSysFile faVolumeID faDirectory faArchive faAnyFile $00000001 $00000002 $00000004 $00000008 $00000010 $00000020 $00000003F Только чтение Скрытый файл Системный файл Идентификатор тома Каталог Архивный файл Произвольный файл

Пример:для файла устанавливаются атрибуты ‘Скрытый файл’ и ‘Только чтение’.
FileSetAttr('MyFile.zzz', faReadOnly or faHidden);

Функция: FileSize(var Vf): Integer; Модуль: System

Описание: Функция возвращает размер файла, связанного с файловой переменной Vf в байтах. Для файлов типа Record функция возвращает количество записей. Если файл не содержит данных, то функция возвращает 0. Файл должен быть обязательно открыт. Данная функция не применима к текстовым файлам.

Описание: Функция находит файл с набором атрибутов Attr в каталоге и по маске, определенных константой Path. Найденное имя файла записывается в переменную F. Если указанный файл найден, то функция возвращает 0, иначе возвращается код ошибки Windows. Параметр Attr — комбинация нескольких констант атрибутов файла или их значений. Константа Path представляет собой полный путь с маской файла (например, ‘C:\MYDIR\*.ini’ ). Повторный поиск файла производится с помощью функции FindNext. По окончанию поиска необходимо высвободить память, выделенную при вызове функции FindFirst, с помощью процедуры FindClose. Значение констант атрибутов:

Константа Значение Описание
faReadOnly faHidden faSysFile faVolumeID faDirectory faArchive faAnyFile $00000001 $00000002 $00000004 $00000008 $00000010 $00000020 $00000003F Только чтение Скрытый файл Системный файл Идентификатор тома Каталог Архивный файл Произвольный файл

Описание: Функция используется в цепочке FindFirst - FindNext - FindClose для повторного поиска файла. Первый поиск осуществляется с помощью функции FindFirst. Функция FindNext возвращает следующий найденный файл, удовлетворяющий условиям поиска определенным при вызове функции FindFirst. В случае успешного выполнения, функция FindNext возвращает 0, а в случае возникновения ошибки — код ошибки Windows. По окончанию поиска необходимо высвободить память с помощью функции FindClose.

Функция: IOResult: Integer; Модуль: System

Описание: Функция возвращает статус ошибки последней выполненной операции ввода/вывода. Использование данной функции возможно только при отключенной проверке ошибок директивой компилятора <$I->. При возникновении ошибки ввода/вывода, все последующие операции ввода/вывода будут игнорироваться до тех пор, пока не будет сделано обращение к функции IOResult. Вызов IOResult очищает внутренний флаг ошибки. Альтернативным способом обработки ошибок ввода/вывода является использование механизма обработки исключительных ситуаций, который включается директивой компилятора <$I+>.

Функция: RenameFile(const OldName, NewName: string): Boolean; Модуль: SysUtils

Описание: Функция переименовывает файл OldName в NewName. При успешном выполнении возвращает True, а в случае ошибки False.

Пример:
begin
if RenameFile('OLD.TXT', 'NEW.TXT') then
MessageDlg(Файл переименован!', mtInformation, [mbOk], 0)
else
ErrorMsg('Невозможно переименовать файл!');
end;

| следующая лекция ==>
Современные способы и средства тушения пожаров | Работа с текстовыми файлами

Дата добавления: 2014-01-07 ; Просмотров: 876 ; Нарушение авторских прав? ;

Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет

Блог GunSmoker-а

. when altering one’s mind becomes as easy as programming a computer, what does it mean to be human.

17 октября 2011 г.

Сериализация — файлы в стиле Pascal

Оглавление

Общие сведения

В языке Pascal (и, следовательно, Delphi) есть встроенные средства по работе с файлами, не зависящие от нижележащей операционной системы.

В отличие от файловых API уровня операционной системы, файлы Pascal ориентированы на работу с типами данных языка (а не нетипизированным байтовым потоком, как это имеет место для API операционной системы, которая понятия не имеет про типы данных языка Pascal) и включают в себя высокоуровневую оболочку для работы со строками и наборами однородных данных. Поэтому работа с файлами Pascal удобнее, чем обращение к API операционной системы.

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

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

Сразу же замечу, что я не буду рассказывать для совсем уж начинающих — тут будет подробное изложение. Предполагается, что вы уже прочитали какую-то «книжку по Delphi».

Всего в языке есть три файловых типа:

  • текстовые файлы ( var F: TextFile; )
  • типизированные файлы ( var F: file of Тип-Данных; )
  • нетипизированные файлы ( var F: file; )

Нетипизированные файлы являются самым общим типом, а текстовые и типизированные файлы — обёрткой над нетипизированными файлами, частным случаем. Они предоставляют более удобные способы работы, путём наложения ограничений на содержимое файла.

Для начала стоит немного прояснить терминологию. Вообще говоря, файлы в системе однородны: любой файл — это набор байтов. Не существует какого-то жёсткого разделения файлов по типам. Тем не менее, часто используются следующие термины для какой-то классификации файлов по содержимому.

Под текстовым файлом понимают файлы, содержащие читабельный для человека текст в кодировках ANSI, UTF-8 или Unicode. Текст представлен в явном виде, при этом некоторые специальные символы (с кодами от 0 до 31) являются специальными — они всегда имеют один и тот же смысл и обычно отвечают за форматирование текста: перенос строк, табуляцию и т.п. Обычно текстовыми файлами не называют документы — файлы, содержащие текст, но оформленные в формате определённой программы (вроде Word), потому что кроме самих данных (текста) такие файлы содержат служебную мета-информацию (заголовки, данные форматирования, атрибуты и т.п.).

В Pascal и Delphi в настоящий момент поддерживаются только текстовые файлы в кодировке ANSI. Файловые типы Pascal считаются устаревшим средством — появившись в языке давно, они уже не развиваются. В те далёкие дни люди мало волновались о кодировках, а о Unicode и UTF-8 и слыхом не слыхивали. Поэтому вы не сможете работать с текстовыми файлами, отличными от канонического ANSI-формата (кодовая страница ANSI, без BOM).

Примечание: начиная с Delphi XE2 (год выхода 2011), файлы Pascal впервые за пару десятков лет получили обновление API: теперь становится возможным указывать кодировку файла, которая может быть отличной от системной кодовой страницы, но вы всё ещё не можете использовать BOM.

Как я уже сказал, «текстовый файл» — это просто удобный ярлык, навешиваемый на файл, чтобы как-то охарактеризовать его содержимое. Это не однозначная и неизменная характеристика. Вы можете открыть текстовый файл в двоичном режиме и вы можете открыть произвольный бинарный файл как текстовый (весь вопрос в осмысленности результатов от таких действий; если первое ещё имеет смысл, то открытие двоичного файла как текстового — весьма сомнительная операция).

Типизированные файлы содержат записи одного типа и фиксированной длины. Чаще всего компонентами файла выступают именно записи ( record ), но это может быть и любой другой тип фиксированного размера. К примеру, текстовый файл можно открыть как типизированный — file of AnsiChar .

Наконец, под нетипизированными файлами понимают файлы произвольной, нерегулярной структуры. Это означает открытие файла в двоичном режиме — как набор байт, без какой-либо предопределённой структуры. Именно в этом режиме работают файловые API операционной системы. В подобном режиме можно открыть любой файл и это всегда будет иметь смысл.

Следует заметить, что понятие «типизированный файл» может трактоваться в двух смыслах. Во-первых, про файл можно говорить, что он типизированный в смысле строгого определения типизированного файла Pascal. Т.е. это файл, определяемый как » file of что-то «, состоящий из набора блоков одинаковой длины. Иными словами, это файл-массив однотипных элементов. Но на практике «типизированный файл» может употребляться и в более широком смысле — как файл с однородными данными. При этом файл не обязан состоять исключительно из последовательности записей, и сами записи файла не обязаны иметь одинаковый размер. К примеру, в начале файла может быть записан заголовок (сигнатура, контрольная сумма, число записей, версия файла и т.п.), а за ним идти набор записей одинакового вида (скажем, три числа и строка), но записи будут иметь переменную длину (строка разной длины). Такой файл могут называть типизированным (в смысле однородности его данных), но надо понимать, что он не будет типизированным в смысле языка Pascal — и работать с ним нужно будет как с нетипизированным, двоичным файлом. Применение термина «типизированный файл» к файлам нерегулярной структуры не корректно. Примером такого файла является .exe файл: в нём содержится первичный заголовок, который ссылается на дополнительные заголовки, в нём есть секции кода и данных (произвольных размеров), оглавление ресурсов (и сами ресурсы) и т.п. Все части файла имеют разную длину и разную структуру.

Общие принципы работы с файлами Pascal

Работа с любыми типами файлов имеет общие элементы, которые мы сейчас и рассмотрим.

Во-первых, работа с файлами в стиле Pascal почти всегда следует одному шаблону (кратко):

  1. AssignFile
  2. Reset/Rewrite/Append
  3. работа с файлом
  4. CloseFile

Подробно:

  1. Вы начинаете с объявления файловой переменной нужного типа. В зависимости от выбранного вами вида файла, вам нужно использовать var F: TextFile; var F: file of Тип-Данных; или var F: file; (текстовый, типизированный и двоичный файл соответственно), где «Тип-Данных» является типом данных фиксированного размера.

    Вы ассоциируете переменную с именем файла. Делается это вызовом AssignFile . Которая имеет прототип: Примеры вызова: Как видите — вы можете указывать любое допустимое имя файла с путём или без, но по соображениям надёжности кода я рекомендую вам всегда указывать полностью квалифицированное имя файла.

    Параметр CodePage является необязательным и он появился только начиная с Delphi XE 2. Он применим только для текстовых файлов. Если он не указан, то используется DefaultSystemCodePage , что для «русской Windows» равно Windows-1251.

    Он указывает кодовую страницу для выполнения перекодировки текста перед записью и после чтения данных из файла. Например: Текстовый файл должен быть в указанной вами кодовой странице. Кодовая страница — любая из принимаемых функцией WideCharToMultiByte (или её аналога на не Windows платформах). Файл не может иметь BOM. Так что на практике эта возможность полезна только для открытия ANSI файлов в кодировке, отличной от системной, но не текстовых файлов в UTF-8 и UTF-16, которые почти всегда имеют BOM.

    Данная операция НЕ открывает файл. Она просто записывает имя файла в файловую переменную. Так что когда вы откроете файл в будущем (как правило — сразу же после этой операции), то будет открыт именно файл с указанным тут именем.

    Данная операция всегда выполняется успешно, но вам нужно быть внимательным и никогда не вызывать её для уже открытых файлов — это приведёт к утечке открытых описателей файла (фактически, AssignFile просто тупо затирает нулями переменную перед выполнением своей работы; так что, чтобы там у вас ни было — оно будет потеряно). Собственно, эта операция нужна не столько для ассоциации с файловым путём, сколько для инициализации переменной. Как правило, за всё время жизни файловой переменной, эта операция применяется к ней единственный раз — первым действием.

    В Pascal вместо AssignFile используется Assign . Это ровно эта же процедура, просто в Delphi Assign переименовали в AssignFile , чтобы избежать конфликтов имён с другим кодом, который тоже использует имя Assign (к примеру — форма, компоненты, да и любой TPersistent ). Assign всё ещё существует в Delphi, так что любой старый код может быть перекомпилирован в Delphi и он будет работать. Но для нового кода вам лучше использовать AssignFile .

    Далее файл открывается. Открывать файл можно в трёх режимах: чтение, запись и чтение-запись. Как несложно сообразить, при открытии файла в режиме чтения из него можно только читать, но не писать — и так далее. Таким образом, всего у файловой переменной может быть 4 режима: закрыт, открыт на чтение, открыт на запись и открыт на чтение-запись (любые другие значения указывают на отсутствие инициализации файловой переменной — т.е. закрытый файл): Открытие файла выполняется с помощью функций Reset , Rewrite и Append .

    Что касается общих моментов: Rewrite создаёт новый файл; Reset открывает существующий файл, а Append является модификацией Reset и открывает файл для дополнения: т.е. после открытия файла переходит в его конец для дозаписи данных. Append применима только к текстовым файлам.

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

    1. Rewrite создаёт новый файл. Если файл с таким именем уже существует, то он удаляется и вместо него создаётся новый файл. Если файловая переменная уже открыта к моменту вызова Rewrite , то файл закрывается и пересоздаётся. После открытия файл позиционируется на начало файла, а функция EOF возвращает True — указывая на конец файла.
    2. Reset открывает существующий файл в режиме, указываемом в глобальной переменной FileMode (по умолчанию — чтение-запись; возможные значения — только чтение, только запись и чтение-запись). Если файл не существует или не может быть открыть в нужном режиме (заблокирован, отказ доступа) — то возникнет ошибка. Если файловая переменная уже открыта к моменту вызова Reset , то файл закрывается и открывается заново. После открытия файл позиционируется на начало файла, а функция EOF возвращает True , если файл существует и имеет размер 0 байт или (обычно) False — если файл существует и имеет ненулевой размер.
    3. Append применимо только к текстовым файлам и будет рассмотрена ниже.

    Глобальная переменная FileMode является именно глобальной переменной, а потому установка доступа не является потоко-безопасным действием. В любом случае, переменная может содержать комбинацию (через «or») следующих флагов: Вы можете указать один флаг вида fmOpenXYZ и один флаг из второй группы. Первый флаг определяет режим открытия: только чтение ( fmOpenRead ), только запись ( fmOpenWrite ) или чтение-запись ( fmOpenReadWrite ), вторые флаги определяют режим разделения файла: без разделения ( fmShareExclusive ), запретить другим читать ( fmShareDenyRead ), запретить другим писать ( fmShareDenyWrite ) и без ограничений ( fmShareDenyNone ). И два флага являются специальными. Флаги разделения используют устаревшую deny-семантику MS-DOS, в отличие от современного API. См. также: взаимодействие флагов режима открытия и разделения.

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

    Затем идёт работа с файлом — чтение и/или запись данных. Эти операции специфичны для разных типов файловых переменных. Их мы отдельно рассмотрим ниже.

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

    Примечание: аналогично AssignFile (см. выше), CloseFile является переименованной Close , которая тоже всё ещё доступна, но чаще всего замещается другим кодом (к примеру — Close у формы). Всегда используйте CloseFile в новом коде.

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

Обработка ошибок

Тут надо сказать, что обработка ошибок работы с файлами Pascal весьма запутывающа. Дело в том, что обработку ошибок подпрограммы ввода-вывода файлов Pascal производят в двух режимах — которые переключаются весьма нестандартно: опцией компилятора. Она называется I/O Checking и расположена на вкладке Compiling (Compiler в старых версиях Delphi) в опциях проекта в Delphi (Project/Options). Что ещё хуже — эта настройка может быть изменена прямо в коде, используя директиву компилятора. В коде можно использовать <$I+>для включения этой опции и <$I->для выключения.

Итак, если эта опция выключена (либо в коде стоит <$I->), то обработку ошибок любых функций по работе с файлами в стиле Pascal (кроме AssignFile , которая всегда успешна) нужно проводить так: вам доступна функция IOResult , которая возвращает статус последней завершившейся операции. Если она вернула 0 — то операция была успешно выполнена (файл открыт, данные записаны и т.п.). Если же она возвращает что-то иное — произошла ошибка. Какая именно ошибка — зависит от значения, которое она вернула, которое (значение) представляет собой код ошибки. Возможные коды ошибок можно посмотреть здесь (только не закладывайтесь на неизменность этих кодов и неизменность таблицы). Помимо ошибок ввода-вывода, вы можете получать и системные коды ошибок. Их список можно увидеть в модуле Windows. Откройте его и запустите поиск по «ERROR_SUCCESS» (без кавычек). А ниже вы увидите список системных кодов ошибок. Наиболее частые ошибки при работе с файлами — ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, ERROR_ACCESS_DENIED, ERROR_INVALID_DRIVE, ERROR_SHARING_VIOLATION. Но вообще код может быть почти любым. В любом случае, вам доступен только код ошибки, но не её текстовое описание. Если произошла ошибка, то все последующие вызовы функций ввода-вывода будут игнорироваться, пока вы не вызовете IOResult .

Итак, это старый режим обработки ошибок, который пришёл в Delphi из языка Pascal. С ним код выглядит примерно так: Вызов функции очищает код ошибки, так что если вы хотите обработать ошибку, нужно поступать так: Поскольку ошибка блокирует вызовы функций ввода-вывода, то обработку ошибок удобно делать один раз — в конце работы. Например: Этот код основан на том факте, что если при работе с файлом возникнет ошибка (к примеру — при открытии файла в момент вызова Rewrite из-за того, что в Edit1 указано недопустимое имя файла), то все нижеследующие функции не будут ничего делать, а код ошибки будет сохранён до вызова IOResult .

Обратите внимание, что правило «ничего не делать при ошибке» не распространяется на CloseFile . Вот почему мы вставили обработку ошибок в самый конец, а не до CloseFile .

Окей, с этим способом всё. Теперь, если вы включаете опцию I/O Checking или используете <$I+>, то функция IOResult вам не доступна, а всю обработку ошибок берут на себя сами функции ввода-вывода: если при вызове любой из них возникнет ошибка — функция сама обработает её путём возбуждения исключения (если модуль SysUtils не подключен — то возбуждением run-time ошибки; подробнее — тут). Исключение имеет класс EInOutError : Собственно, код в этом режиме всегда будет выглядеть так: А при возникновении проблем — у вас будет исключение, которое в стандартной VCL Forms программе в конечном итоге обрабатывается показом сообщения:

Я допускаю, что вы можете не очень быть знакомы с работой с исключениями (и в таком случае вам можно начать с этой статьи), но я бы всё же рекомендовал использовать режим <$I+>по одной очень простой причине: с исключениями поведение по умолчанию — показ ошибки; в режиме <$I->— скрытие и игнорирование. Иными словами, если в <$I->по незнанию или из-за лени вы опустите обработку ошибок, а при выполнении программы ошибка всё же возникнет — вы останетесь ни с чем: код просто не работает и вы понятия не имеете почему. С исключениями же такое невозможно: вам нужно специально прикладывать усилия, чтобы скрыть ошибку, так что это не может произойти случайно, по недосмотру.

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

Персональное примечание: напомню, что именно запутанность обработки ошибок в файлах Pascal привела к обнаружению вируса Virus.Win32.Induc.a.

В любом случае, это всё. И нам наконец-то можно приступить к обсуждению непосредственно работы с файлами.

Текстовые файлы

Итак, текстовый файл — это обычный файл, открываемый через переменную типа TextFile , для которого делается предположение о чисто текстовом содержимом. Тип TextFile в Delphi имеет псевдоним Text — это текстовый тип в Pascal. И снова: тип был переименован, старый Text всё ещё существует по соображениям совместимости, но в новых программах нужно использовать тип TextFile .

Когда вы открываете текстовый файл, его содержимое интерпретируется специальным образом: предполагается, что файл содержит последовательности читабельных символов, организованных в строки, при этом каждая строка заканчивается маркером end-of-line («конец строки»). Иными словами, текстовый файл трактуется не как просто file of Char , а с дополнительной смысловой нагрузкой. Для текстовых файлов есть специальные формы Read и Write , на которые мы посмотрим чуть позже.

В Delphi есть три стандартные глобальные переменные типа текстовых файлов: Input для чтения или Output для вывода — это специальные имена для стандартных каналов ввода-вывода; ещё есть ErrOutput — стандартный канал вывода ошибок, по умолчанию он направляется в канал вывода, но вызывающая программа может отделить его. Соответственно, Input открывается только для чтения и обычно представляет собой клавиатуру в консольных приложениях (если ввод не был перенаправлен), а остальные два — только для записи (и обычно представляют собой экран). Эти файловые переменные открываются автоматически. В Windows они открываются только для консольных программ, но на других платформах это может быть и не так.

В любом случае, для открытия текстовых файлов можно использовать Rewrite (создание), Reset (открытие) и Append (дозапись в существующий файл). Все три используются одинаково — им передаётся переменная файлового типа. Больше аргументов у них нет. Особенность текстовых файлов: Rewrite открывает файл (вернее — создаёт) в режиме только запись, Reset всегда открывает файл в режиме только чтение, а Append открывает файл в режиме только запись. Текстовые файлы нельзя открыть в режиме чтение-запись.
Append аналогична Reset , только устанавливает текущую позицию файла в конец и открывает в режиме записи, а не чтения.

После открытия вам доступны процедуры Write , WriteLn , Read и ReadLn для записи и чтения строк (варианты функций с *Ln допустимы только для текстовых файлов). Эти подпрограммы не являются настоящими функциями и процедурами, а представляют собой магию компилятора. Первым параметром у них идёт файловая переменная — она указывает файл, с которым будет производится работа (чтение строк или запись), а далее идёт произвольное число параметров — что пишем или читаем.

Если опустить файловую переменную — будет подразумеваться консоль ( Input и Output ). Это используется для ввода-вывода в консольных программах. Вам необязательно работать со стандартными каналами ввода-вывода именно через файлы Pascal, вы можете использовать и API.

Иными словами, вызовы этих функций имеют форму: Где «что-то» — это одна или более строковых или числовых переменных, указанных через запятую — как обычные аргументы. Мы рассмотрим это чуть позже.

При этом, краткая форма: эквивалентна: В Windows Input , Output и ErrOutput доступны только для консольных программ. Попытка использовать их в GUI приложении приведёт к ошибке (операция над закрытой файловой переменной). Это — частая ошибка новичков. Они забывают указать первым параметром файловую переменную. Эта ошибка не страшна в Windows, поскольку вы тут же увидите проблему при запуске программы, но достаточно коварна на других платформах, где стандартные каналы ввода-вывода могут быть открыты для всех программ. Таким образом, если вы забудете указать файловую переменную, то ваша программа будет работать, не выдавая ошибки — но будет работать неправильно.

Функции с постфиксом Ln отличаются от своих собратьев тем, что используют разделитель строк. Иными словами, Write записывает данные в файл, а WriteLn дополнительно после этого вписывает в файл перенос строки. Т.е. несколько вызовов Write подряд будут писать данные в одну строку. Аналогично, Read читает данные из файла, а ReadLn после этого ищет конец строки и делает переход к следующей строке в файле. В качестве разделителя строк используется умолчание для платформы, если вы пишете в файл, или Enter, если вы работаете с консолью. К примеру, для Windows разделителем строк является последовательности из двух символов #13#10 — известные как CR (carriage return) и LF (line feed), они имеют коды 13 и 10, соответственно. По историческим причинам выбор разделителя строк зависит от платформы. Вы можете изменить умолчание вызовом SetLineBreakStyle , но замечу, что работа с файлами другой платформы — это достаточная головная боль. Я не буду это подробно рассматривать. Часто наилучшее решение — предварительная нормализация данных и файлов. В частности, в Delphi есть функция AdjustLineBreaks.

Read читает все символы из файла вплоть до конца строки или конца файла, но она не читает сами маркеры. Чтобы перейти на следующую строчку — используйте ReadLn . Если вы не вызовите ReadLn , то все вызовы Read после встречи маркера конца строки будут возвращать пустые строки (для чисел — нули). Опознать конец строки или конец файла можно с помощью функций EoLn и EoF (или функций SeekEoLn и SeekEoF — и эти функции не следует путать с функцией Seek ). Если же читаемая строка длиннее, чем аргумент у Read / ReadLn , то результат обрезается без возбуждения ошибки. Но если вы читаете числа, то Read пропускает все пробелы, табуляторы и переносы строк, пока не встретит число. Иными словами, при чтении чисел они должны отделяться друг от друга пробелами, табуляторами или размещаться на отдельных строках. При чтении строк вы должны переходить на следующую строку сами.

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

В общем случае параметр выглядит так:

Где в квадратных скобках указываются опциональные (необязательные) части. OutExpr — это само выражение для записи. Оно может быть переменной, константой или непосредственным значением. MinWidth и DecPlaces являются спецификаторами форматирования и должны быть числами. MinWidth указывает общую длину вывода и должно быть числом большим нуля. По необходимости слева добавляется нужное количество пробелов. А DecPlaces указывает число знаков после десятичной точки и применимо только при записи чисел. Если эти данные не указаны, то используется научный формат представления чисел. Форматирование значений при выводе — наследие Pascal, где не было функций форматирования строк. В современных программах предпочтительнее использовать функцию Format и её варианты. Этот современный вариант форматирования данных является стандартным решением в Delphi и предоставляет больше возможностей.

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

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

Далее необходимо заметить, что переменные текстового файлового типа имеют буфер. Все данные, записываемые в файл, на самом деле записываются в этот буфер. И лишь при закрытии файла или переполнения буфера данные сбрасываются на диск. Аналогичные действия производятся и при чтении файла. Это делается для оптимизации посимвольного ввода-вывода. Буфер можно сбросить и вручную в любой момент — с использованием подпрограммы Flush . По умолчанию размер буфера равен 128 байтам, но его можно изменить на произвольное значение вызовом SetTextBuf .

Текстовые файлы не поддерживают позиционирование.

Типизированные файлы

Типизированный файл — это очень простая БД в виде «array of что-то». Как уже было сказано, «что-то» должно иметь фиксированный размер в байтах, поэтому строки и динамические массивы хранить нельзя (но можно — короткие строки или статические массивы символов). Для открытия файлов доступны Rewrite и Reset . Здесь нет никаких особенностей по сравнению с вышеуказанными общими принципами. Запись и чтение из файла осуществляется с помощью Write и Read .

В отличие от текстовых файлов, типизированные и нетипизированные файлы поддерживают позиционирование. Вы можете установить текущую позицию в файле с помощью Seek . Процедура принимает два параметра — файл и номер позиции, на которую нужно переместиться. Положение отсчитывается не в байтах, а в размере записи файла. Иными словами, если вы работаете с, к примеру, file of Integer , то Seek(F, 0) переместит вас в начало файла, Seek(F, 1) — ко второму элементу (т.е. через 4 байта от начала файла), Seek(F, 2) — к третьему (через 8 байт), а Seek(F, FileSize(F)) — в конец файла. Т.е. функция FileSize тоже возвращает размер файла не в байтах, а в записях. Этот размер совпадает с размером в байтах только для file of byte и аналогичных типов — с однобайтовыми записями. Текущую файловую позицию (снова в записях) всегда можно узнать вызовом FilePos .

Ещё одной особенностью типизированных (и нетипизированных) файлов является функция Truncate . Она удаляет содержимое файла за текущей позицией. После её вызова функция EoF возвращает True .

Нетипизированные файлы

Нетипизированные файлы заполняют пробел в файлах Pascal, позволяя открывать произвольные файлы в двоичном режиме и осуществлять побайтовый доступ. Данный тип файлов не имеет никакого преимущества перед другими методами работы с файлами. В частности, почти всегда для нетипизированного доступа к файлу оказывается предпочтительнее TFileStream (мы рассмотрим его в другой раз).

Для нетипизированных файлов нам доступны Rewrite и Reset — равно как и для типизированных файлов. Но тут есть одно важное отличие: для нетипизированных файлов эти процедуры принимают два параметра. Первый параметр, как обычно, файловая переменная. А второй параметр — размер блока. Размер блока измеряется в байтах и является аналогом размера записи у типизированных файлов. Размер блока влияет на все подпрограммы работы с нетипизированными файлами, которые принимают размеры или позицию. Все они подразумевают указание размеров/позиции в блоках, а не байтах. Вы можете указать 1, чтобы производить измерения в байтах. Плохая новость — второй параметр является опциональным, его можно не указывать. Проблема тут в том, что если вы его не укажете, то размер блока по умолчанию будет 128 байт — не самое очевидное поведение.

Далее, для чтения и записи в нетипизированный файл вместо Read и Write используются функции BlockRead и BlockWrite . Обе они используются одинаково: первый параметр — файловая переменная, второй параметр — что пишем/читаем, третий параметр — сколько пишем/читаем (в блоках). Функция возвращает сколько реально было прочитано/записано. Если блок прочитан/записан целиком, то результат равен третьему параметру. У обеих функций есть перегруженные варианты, у которых результат функции возвращается четвёртым параметром.

Замечу, что второй параметр — нетипизированный. Это значит, что компилятор не выполняет проверок типа. И вам лучше бы не напутать, что туда передавать. Я в первую очередь сейчас говорю про указатели и динамические типы. К примеру: Фух, достаточно сложно. Но только если вы не понимаете как работают указатели.

Следует заметить, что достаточно часто вместо использования типизированного файла оказывается проще открыть файл в двоичном режиме (как нетипизированный) и загрузить/сохранить все данные за раз — вместо организации цикла. К примеру (обработка ошибок убрана):
Разумеется, нетипизированные файлы поддерживают позиционирование — ровно как и типизированные файлы. Только не забывайте про измерение в блоках, а не байтах.

Прочие подпрограммы и особенности

Хотя типы файловых переменных являются «чёрным ящиком», но внутренне они представлены записями TTextRec (для текстовых файлов) или TFileRec (для всех прочих файлов). Обе записи объявлены в модуле System : Вам не нужны эти записи для обычной работы, но иногда могут быть ситуации, когда вам нужно получать доступ к полям записи. Сделать это можно простым приведением типа: Примечание: структура записей зависит от версии вашей Delphi. Прежде чем использовать код, который работает с этими записями или объявляет аналогичные хак-записи — убедитесь, что код написан для вашей версии Delphi или адаптируйте объявления и код.

Практика

Все примеры ниже приводятся с полной обработкой ошибок для режима <$I+>. Примеры используют файл в папке с программой. Это удобно для тестирования и экспериментов, но, как указано ранее, этого нужно избегать в реальных программах. После тестирования и перед использованием кода в релизе вы должны заменить папку программы на подпапку в Application Data.

Практика: текстовые файлы

  1. Одно значение: Double Обратите внимание, что запись чисел всегда использует фиксированный формат числа — вне зависимости от региональных установок. Иными словами, конвертация чисел в строки и обратно выполняется процедурами Str и Val . Это имеет как плюсы, так и минусы.

С одной стороны, файл, созданный на одной машине, без проблем прочитается на другой.

С другой стороны, текстовый файл, очевидно, предназначен для редактирования человеком. Иначе зачем делать его текстовым? А человек вправе ожидать, что числа будут использовать «правильный формат». К примеру, для России это — использование запятой в качестве разделителя целой и дробной частей, а не точки. Простого решения этой проблемы для текстовых файлов в стиле Pascal нет.

Одно значение переменного размера: String Ключевой момент при записи данных с динамическим размером — размещать каждое такое значение на отдельной строке. Тогда размер данных = размеру строки.

Набор однородных значений: array of Double Обратите внимание, что записываем мы все значения в одну строчку — поэтому нам нужно вставить разделитель (пробел). Кроме того, мы могли бы также писать каждое число на отдельной строке — используя WriteLn . Тогда пробел был бы уже не нужен.

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

Поэтому вместо этого я показал, как вы можете считать файл произвольной структуры — лишь бы в нём были бы числа. Для этого мы делаем цикл чтения, пока не будет встречен конец файла ( while not SeekEof(F) do ), а в самом цикле считываем и добавляем в массив каждое число. При этом мы пользуемся тем фактом, что Read при чтении числа будет пропускать все пробельные символы, включая переносы строк. Вот почему нам не нужно явно вызывать ReadLn .

Ещё один момент — использование SeekEoF вместо просто EoF . Если бы мы использовали EoF , то тогда в массив добавлялся бы ноль в конец, если в конце файла стоит несколько пробелов или пустых строк.

Набор однородных значений переменного размера: array of String Здесь всё оказывается ещё проще — динамические данные должны размещаться на отдельной строке, так что мы просто используем WriteLn / ReadLn . Обратите внимание, что в этом случае, поскольку мы записываем строки, то нет никакой возможности отличить пустую строку в конце файла — часть ли это данных или просто человек случайно добавил её. Если в ваших данных пустые строки недопустимы, то вы можете заменить EoF на SeekEoF , как это сделано в предыдущем примере.

Запись — набор неоднородных данных: Тут всё достаточно прозрачно — каждое поле на новой строке.

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

Массив из записей внутри записи — составные данные: С вложением самих записей проблем не возникает — я даже не буду писать пример, т.к. он эквивалентен предыдущему. Просто выпишите в ряд WriteLn полей TCompose . Для полей-записи вместо одного WriteLn вам нужно будет написать несколько — по одному на каждое поле вложенной записи. Ну а ReadLn будут зеркальным отражением WriteLn .

Но вот вложение массива записей уже является непреодолимым препятствием для общего случая. Дело в том, что в текстовом файле нет возможности как-то указать размер вложенных данных, ведь обычная техника записи динамических данных в текстовый файл — использование разделителей (чаще всего — переноса строк). В частных случаях вы можете найти решение. Скажем, отделять поле Related пустой строкой от следующего элемента/поля. Но в общем случае приемлемого решения нет — вам нужно использовать нетипизированный файл. В некоторых случаях вы можете предложить введение формата в текстовый файл. Вроде INI, XML, JSON и т.п. Но на это мы посмотрим в следующий раз.

Практика: типизированные файлы

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

Тут надо сделать примечание, почему вообще для этого примера выбран именно тип Double , а не Extended , который в Delphi является де-факто стандартом для чисел с плавающей запятой. Дело в том, что Extended зависит от платформы. Его размер может меняться. Так что если вы компилируете, скажем 32-битную и 64-битную программы — у них размер Extended будет разным. Что означает, что из одной программы вы не сможете прочитать данные, созданные в другой. Это не проблема, если вы планируете работу только в одной платформе — можете спокойно использовать Extended . В противном случае вам нужно использовать Double . Ну а если вам нужно прочитать Extended , созданный на другой платформе, то вы можете использовать тип TExtended80Rec (появился, начиная с Delphi XE2, где, собственно, и появилась поддержка нескольких платформ) вместо Extended .

Аналогично, по этой же причине вам следует избегать Integer и Cardinal при работе с типизированными файлами — потому что это generic-типы, размер которых может меняться. Используйте вместо них LongInt и LongWord соответственно.

Одно значение переменного размера: String . Сделать это для типизированных файлов невозможно. В типизированный файл (в смысле файловых типов языка Pascal) нельзя записывать данные переменного (динамического) размера. Для динамических данных нужно использовать либо текстовые, либо нетипизированные файлы. Что вы можете сделать — так это использовать какое-то ограничение.

К примеру, если брать строки, то вы можете использовать ShortString — это ограничит ваши данные ANSI и 255 символами. Ещё вариант — статический массив символов. Скажем array[0..4095] of Char ( AnsiChar / WideChar ). Обратите внимание, что запись в файл ShortString или массива из символов — это не аналог текстовых файлов, потому что кроме значимого текста в файле появляется т.н. padding — мусорные данные, не несущие смысловой нагрузки, а служащие для дополнения данных до нужного размера. Вы можете вызывать FillChar или ZeroMemory для предварительной очистки данных перед записью — чтобы визуально подчеркнуть неиспользуемость дополнения.

Надо понимать, что чем больше (по байтовому размеру) вы возьмёте тип, тем больше места у вас будет тратиться зря (на padding), если в основной массе у вас короткие строки. С другой стороны, если вы возьмёте недостаточно большой тип, то ваши данные будут обрезаться. Так что подобный вариант далеко не всегда возможен — а только, если вы можете предложить подходящее ограничения размера.

Здесь и далее я не буду приводить пример — он всегда эквивалентен предыдущему примеру с данными фиксированного размера. Только замените типы.

Набор однородных значений: array of Double Обратите внимание, что нам не нужен разделитель, поскольку элементы имеют фиксированный размер. Кроме того, нет проблемы с пробелами в конце, ранее решаемой SeekEoF . Кроме того, фиксированность элементов позволяет узнать длину массива заранее — по размеру файла, что в итоге позволяет написать более эффективный код.

Запись — набор неоднородных данных: Аналогично второму примеру, записать неоднородные данные в типизированный файл невозможно. Если вы объявите file of LongWord , то вы не сможете записать в него строку и наоборот. В общем, нужно использовать текстовые или нетипизированные файлы.

Вы можете подумать, что вы могли бы объявить file of TData — ну, с заменой динамических строк на фиксированные аналоги, конечно же. А затем использовать первый пример. Да, это будет работать для конкретного объявления TData , но только этот пример — не на запись в файл record -а, а на запись неоднородных данных.

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

Практика: нетипизированные файлы

  1. Одно значение: Double
    Обратите внимание на 1 у Rewrite / Reset . Конечно, мы могли бы использовать вместо неё SizeOf(Double) . Но это фактически означало бы, что мы используем нетипизированный файл как типизированный. А в чём тогда смысл примера?

Одно значение переменного размера: String Данный случай прост — размер данных определяется по размеру файла. Для примера я выбрал AnsiString , а не String по друм причинам — во-первых, String — это псевдоним либо на AnsiString , либо на UnicodeString , в зависимости от версии Delphi. Иными словами, тут получается ситуация, аналогичная ситуации с Extended в разделе примеров для типизированных файлов. Так что вам нужно использовать явные типы — AnsiString , WideString (или UnicodeString ), а не String , иначе файл, созданный в одном варианте программы, нельзя будет прочитать в другом варианте программы.

Во-вторых, используя AnsiString , я показал, как вы можете загрузить в строку весь файл целиком, «как есть». Хотя, если подобный подход использовать в реальных программах, то уж лучше использовать array of Byte или хотя бы RawByteString — чтобы подчеркнуть двоичность данных.

Набор однородных значений: array of Double Данный пример эквивалентен примеру с типизированными файлами. Только теперь мы используем двоичный доступ, без учёта типа — так что нам приходится указывать явно все размеры. Вообще говоря, это общий принцип — работа с нетипизированными файлами и фиксированными размерами эквивалента типизированным файлам с учётом коэффициента размера.

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

Обратите внимание, что не имеет значения, какой индекс используется внутри выражения у SizeOf . Более того, не требуется даже наличие (существование) этого элемента. Это потому, что мы не обращаемся к нему — мы только просим у компилятора его размер. Это, по сути, константа. Так что всё выражение вообще не вычисляется — оно просто заменяется числом. Это удобный трюк для написания подобного кода, потому что это удобнее, чем писать тип явно: SizeOf(Double) . Почему? А что, если мы изменим объявление типа с Double на Single ? И забудем обновить SizeOf ? Тогда это приведёт к порче памяти — т.к. писаться или читаться будет больше, чем реально есть байт в элементе. Это выглядит не очень страшно для массива из Double , но рассмотрите вариант, скажем, строки — изменение размера Char гораздо более вероятно. А вот если мы используем форму SizeOf как в примере, то такой проблемы не будет — размер изменится автоматически.

Набор однородных значений переменного размера: array of String С записью набора динамических данных возникает проблема — как отличить один элемент от другого? Мы не можем более использовать переход на другую строку, как это было с текстовыми файлами. Тут есть несколько вариантов.

Самый простой и очевидный — ввести разделитель данных. Т.е. элементы отделяются друг от друга специальным символом. В качестве такого чаще всего выступает нулевой символ (#0) — это аналог разделителя строк в текстовых файлах. Тогда чтение-запись сведётся к примеру два. Но я не стал показывать этот путь, т.к. он очевидно вводит ограничение на возможные данные: теперь данные не могут содержать в себе разделитель (каким бы вы его ни выбрали). Конечно, вы можете его экранировать, но гораздо проще будет выбор другого подхода.

И я его показал — это явная запись размера данных до записи самих данных. Т.е. мы пишем два значения для каждого элемента: длину и сами данные.

Кроме того, в этом же примере показано, как можно сделать так, чтобы внутри программы работать с хорошо знакомым String , а в файле хранить фиксированный тип ( AnsiString / RawByteString или WideString / UnicodeString ). Вообще говоря, даже если вы работаете на Delphi 7 или любой другой версии Delphi до 2007 включительно — я бы рекомендовал всегда писать Unicode-данные в формате WideString во внешние хранилища.

Обратите внимание, что в качестве счётчика длины используется LongInt , а не Integer — по причинам, указанным выше для типизированных файлов: String , Extended , Integer и Cardinal могут менять свои размеры в зависимости от окружения — поэтому мы используем другие типы, которые гарантировано всегда имеют один и тот же размер.

Запись — набор неоднородных данных: В отличие от типизированных файлов, для нетипизированных файлов нет никаких проблем с записью неоднородных данных — вы просто пишете одно за другим. Данные фиксированного размера самодокументируются, а для динамических данных вы пишете сначала их размер, а затем сами данные. При чтении повторяете всё это в обратном порядке.

Кстати, я бы вынес запись динамических данных в отдельные служебные подпрограммы: Тогда чтение-запись свелись бы к: Выглядит существенно проще и красивее, не так ли? Иллюстрация силы выделения кода в подпрограммы.

Набор (массив) из записей — иерархический набор данных: Для начала хочу сразу же заметить, что странное выражение для поля Salary сделано для обхода бага Delphi. Вообще, там должно стоять просто BlockWrite(F, Values[Index].Salary, SizeOf(Values[Index].Salary)) , но в настоящий момент это выражение даёт ошибку «Variable required», поэтому используется обходной путь: мы берём указатель и разыменовываем его. Вообще говоря, это NOP-операция. А смысл её заключается в потере информации о типе. Это достаточно частый трюк, когда мы хотим запустить свои шаловливые руки под капот языка, минуя информацию типа, но в данном случае он используется для более благих целей: обхода бага компилятора. Вы можете использовать BlockWrite(F, Values[Index].Salary, SizeOf(Values[Index].Salary)) , если ваша версия компилятора это позволяет, или просто выбрать другой тип данных (не Currency ).

В любом случае, надо заметить, что достаточно часто при записи/чтении массива записей новички пытаются сделать такую вещь, как запись элемента целиком ( BlockWrite(F, Values[Index], SizeOf(Values[Index])) ). Это будет работать для записей фиксированного размера, не содержащих динамические данные (указатели). Ровно как это работает для типизированных файлов. Но если в записях у вас встречаются строки, динамические массивы и другие данные-указатели, то этот подход не будет работать. Собственно, если вы используете типизированные файлы, то компилятор даже не даст вам объявить такой тип данных ( file of String , например, или file of Запись , где Запись содержит String ). Но суть нетипизированных файлов — в прямом доступе, минуя информацию типа. Так что по рукам за это вам никто не даст. Вместо этого код будет просто вылетать или давать неверные результаты. А проблема тут в том, что для динамических данных, поле — это просто указатель. Записывая элемент «как есть» вы запишете в файл значение указателя, но не данные, на которые он указывает. Запись в файл произойдёт нормально, но в файле вы не найдёте своих строк. Чтение из файла тоже пройдёт отлично. Но как только вы попробуете обратиться к прочитанной строке — код вылетит с access violation, потому что указатель строки указывает в космос, на мусор.

Аналогично обсуждению типизированных файлов, самый простой способ решения проблемы (но не всегда достаточный) — замена String в записях на ShortString или статический массив символов. Я не буду рассматривать этот вариант, т.к. он сводится к предыдущим примерам с записью данных фиксированного размера.

Вместо этого в примере я показал уже известную технику: запись длины строки вместе с её данными. Это избавляет вас от всех недостатков ShortString /массива символов, но даёт новый недостаток: теперь вы не можете сохранить данные одной строчкой, вам нужно писать их поле-за-полем.

Массив из записей внутри записи — составные данные: Как видите — здесь нет никаких проблем, вы просто соединяете воедино техники из предыдущих примеров. Мы используем технику с записью счётчика длины для динамических данных в двух местах: при записи строк и при записи массивов (поле Related ).

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

Заметьте, что вы всё ещё должны писать записи по отдельным полям. И если вы меняете объявление записи — вам лучше бы не забыть поменять код, сериализующий и десериализующий запись.

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

Преимущества и недостатки файлов в стиле Pascal

Плюсы:

  • Отлично подходят для начального изучения языка
  • Вы наверняка знаете, как с ними работать, ибо это первый способ работы с файлами, который все изучают
  • Удобство работы с (текстовыми) данными: форматирование и переменное число аргументов
  • Гибкий подход, позволяющий работать с текстовыми, типизированными и произвольными данными
  • Встроенная буферизация даёт прирост производительности при записи небольших кусочков из-за экономии на вызовах в режим ядра
  • Могут быть расширены на поддержку любых файловых устройств, а не только дисковых файлов (т.е. IPC, pipes, сетевых каналов и т.п.) — путём написания своих адаптеров ввода-вывода, называемых «Text File Device Drivers». Подробнее см. Text File Device Drivers в справке Delphi

Минусы:

  • Необходимость ручной сериализации данных
  • Неудобная (и неоднозначная) обработка ошибок
  • Поведение кода зависит от директив компилятора
  • Нет поддержки Unicode и кодировок (улучшено начиная с Delphi XE2)
  • Проблемы с обработкой больших файлов (более 2 Гб)
  • Проблемы с глобальными переменными
  • Проблемы с многопоточностью
  • В некоторых случаях требуется ручной сброс буфера
  • Недостаточная гибкость для некоторых задач
  • Нестандартный код

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

Вывод: это отличный выбор для изучения языка и работы с файлами, но лично я для практических задач предпочитаю держаться подальше от файлов в стиле Pascal, но кто-то может считать это удобным способом. Если текстовые файлы ещё как-то оправдывают своё существование (если вы закроете глаза на их минусы), то типизированные и нетипизированные файлы практически зеркалируют потоки данных, но не имеют над ними никаких преимуществ.

Delphi in a Nutshell by Ray Lischner

Stay ahead with the world’s most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to v > Start Free Trial

No credit card required

Syntax

Description

FilePos returns the current position (as a record number) in the file F . The beginning of the file is position zero. If F is a TextFile , the record size is arbitrarily chosen as the buffer size, which defaults to 128. When Eof(F) is True, FilePos returns the number of records in the file. FilePos is not a real function.

Errors

If the file F is not open, FilePos reports I/O error 103.

Although you can get the file position in a text file, you cannot use it to seek to that position. The Seek procedure works only with binary files. To get a file position of a text file, use the Windows API:

FilePos does not support files larger than 2 GB. See the FileSeek function in the SysUtils unit, or call the Windows API for large files.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  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

Проблемма с BlockRead

03.12.2012, 20:31

BlockWrite и BlockRead
http://www.delphibasics.ru/BlockWrite.php var myFile : File; byteArray : array of byte; .

Blockread file
Здравствуйте!Выбираю фаел через opendialog,скажите как потом считать выбранный фаел в переменную?

Альтернатива AssignFile, BlockRead, BlockWrite
Доброго времени суток. Появилась такая проблема. AssignFile не умеет хавать большие файлы, а мне.

Зацикливание при использовании Blockread
Хочу перезаписать содержимое одного файла в другой. И если открыть картинку или текстовый файл.

Запись/чтение из бинарного файла. BlockRead
Впервые использую BlockRead и BlockWrite, видимо что то не правильно понял. Запись: i : Word; .

FilePos — Функция Delphi

Начинаю перепечатку списка функций и процедур Delphi с сайта [ Ссылки могут видеть только зарегистрированные пользователи. ] (с дополнениями и изменениями).

Процедуры и функции работы с файлами

Для избежания конфликтов, AssignFile заменяет стандартную процедуру Assign в Delphi. Однако для обратной совместимости вы можете использовать Assign. Процедура AssignFile сопоставляет имя внешнего файла с файловой переменной.

F — файловая переменная любого файлового типа, FileName — выражение типа String или выражение типа PChar, если допускается расширенный синтаксис. Все дальнейшие операции с F производятся с внешним файлом.

Не используйте AssignFile с уже открытой файловой переменной.

Procedure CloseFile (var F);

Из-за конфликтов наименования, процедура CloseFile заменяет стандартную процедуру Close из Borland Pascal (сейчас она используется для других целей). Используйте CloseFile, чтобы разорвать связь между файловой переменной и внешним дисковым файлом и закрыть файл.

F — файловая переменная любого файлового типа, открытая процедурами Reset, Rewrite или Append. Внешний файл, связанный с F, полностью модифицируется и затем закрывается, освобождая дескриптор файла для повторного использования.

Дополнительно
Директива <$I+>позволяет вам обрабатывать ошибки во время выполнения программы, используя обработку исключительных ситуаций.
При выключенной директиве <$I->, вы должны использовать IOResult для проверки ошибок ввода — вывода.

Function Eof(var F): Boolean;

(типизированные или нетипизированные файлы)

Function Eof[(var F: Text)]: Boolean;

Проверяет, является или нет текущая позиция файла концом файла.

Eof(F) возвращает True, если текущая позиция файла находится за последним символом файла или если файл пуст; иначе, Eof (F) возвращает False.

Procedure Erase(var F);

Удаляет внешний файл, связанный с F.

F — файловая переменная любого файлового типа.

Перед вызовом процедуры Erase, файл необходимо закрыть.

Function FileSize(var F): Integer;

Возвращает размер в байтах файла F. Однако, если F — типизированный файл, FileSize возвратит число записей в файле.

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

Если файл пуст, FileSize(F) возвращает 0.

F — переменная любого файлового типа.

Function FilePos(var F): LongInt;

Возвращает текущую позицию файла внутри файла.

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

F — переменная любого файлового типа, кроме типа Text.

Procedure Reset(var F [: File; RecSize: Word]);

Открывает существующий файл.

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

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

Procedure Rewrite(var F: File [; Recsize: Word]);

Создает и открывает новый файл.

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

Процедура Rewrite создает новый внешний файл с именем, связанным с F.

Если внешний файл с тем же самым именем уже существует, он удаляется, и создается новый пустой файл.

Procedure Seek(var F; N: LongInt);

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

Текущая позиция файла F перемещается к номеру N. Номер первого компонента файла — 0.

Инструкция Seek(F, FileSize(F)) перемещает текущую позицию файла в конец файла.

Procedure Append(var F: Text);

Открывает существующий текстовый файл для добавления информации в конец файла (дозаписи).

Если внешнего файла с данным именем не существует, происходит ошибка времени выполнения.

Если файл F уже открыт, он закрывается и вновь открывается. Текущая позиция файла устанавливается к концу файла.

Function Eoln[(var F: Text)]: Boolean;

Проверяет, является ли текущая позиция файла концом строки текстового файла.

Eoln(F) возвращает True, если текущая позиция файла — в конце строки или файла; иначе Eoln(F) возвращает False.

Procedure Read(F, V1 [, V2, . Vn]);

(типизированные и нетипизированные файлы)

Procedure Read([var F: Text;] V1 [, V2, . Vn]);

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

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

С переменными типа String Read считывает все символы вплоть до следующей метки конца строки (но не включая ее), или пока функция Eof(F) не примет значение True. Переменной присваивается получившаяся в ре-зультате символьная строка.

В случае переменной целого или вещественного типа процедура ожидает поступления последовательности символов, образующих число по правилам синтаксиса языка Object Pascal. Считывание прекращается при обнаружении первого пробела, символа табуляции или метки конца строки, или в том случае, если функция Eof(F) принимает значение True. Если чи-словая строка не соответствует ожидаемому формату, то происходит ошибка ввода-вывода.

Procedure Readln([var F: Text;] V1 [, V2, . Vn]);

Является расширением процедуры Read и определена для текстовых файлов. Считывает строку символов в файле (включая маркер конца строки) и переходит к началу следующей строки. Вызов функции Readln(F) без па-раметров приводит к перемещению текущей позиции файла на начало сле-дующей строки, если она имеется, в противном случае происходит переход к концу файла.

Function SeekEof[(var F: Text)]: Boolean;

Возвращает признак конца файла и может использоваться только для открытых текстовых файлов. Обычно применяется для считывания числовых значений из текстовых файлов.

Function SeekEoln[(var F: Text)]: Boolean;

Возвращает признак конца строки в файле и может использоваться только для открытых текстовых файлов. Обычно применяется для считывания числовых значений из текстовых файлов.

Procedure Write([var F: Text;] P1 [, P2, . Pn]);

Записывает одну или более величин в текстовый файл.

Каждый параметр записи должен иметь тип Char, один из целочисленных типов (Byte, ShortInt, Word, LongInt, Cardinal), один из типов с плавающей запятой (Single, Real, Double, Extended, Currency), один из строковых типов (PChar, AnsiString, ShortString), или одного из логических типов (Boolean, Bool).

Procedure Write(F, V1, . Vn);

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

Procedure Writeln([var F: Text;] P1 [, P2, . Pn]);

Выполняет операцию Write, затем помещает метку конца строки в файл.
Вызов Writeln(F) без параметров записывает в файл маркер конца строки.
Файл должен быть открыт для вывода.

Все замечания и предложения — на 223356174.

Илон Маск рекомендует:  Ещё о командах ассемблера
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL