while not Eof(F1) do {пока не достигнут конец файла – выполнять}
begin
Read(F1, Ch); {читает один символ из файла F1}
Write(F2, Ch); {пишет один символ в файл F2}
end;
CloseFile(F1); {файл F1 закрыт}
CloseFile(F2); {файл F2 закрыт}
Reset(F1); {F1 снова открыт для чтения}
Rewrite(F2); {F2 снова создан для вывода }
while not Eof(F1) do {пока не достигнут конец файла – выполнять}
begin
Readln(F1, St); {читает строку из файла F1}
Write(F2, St); {пишет строку в файл F2}
end;
CloseFile(F1); {файл F1 закрыт}
CloseFile(F2); {файл F2 закрыт}
end;
Приведенный фрагмент модуля является демонстрационным и предназначен для копирования файла 'T1.TXT' в файл 'WOOF.DOG' . В первом цикле While – do копирование ведется посимвольно, во втором цикле – построчно.
Пример процедуры, записывающей в конец текстового файла строку символов:
Procedure AddStrToTextFile(nF, St:String);
Var f: Text;
Begin
AssignFile(f, nF);
If not FileExists(nF) then Rewrite(f) {не существует, создать и открыть}
Else {иначе}
Begin
Reset(f); {существует, открыть }
Whilenot Eof(f) do Readln(f); {передвинуть указатель в конец файла}
End;
Writeln(f, St); {записать строку }
CloseFile(f); {закрыть файл}
End;
К процедуре можно обратиться, например, так:
Var
S1: String[58];
S2: String[189];
…
AddStrToTextFile('c:\Files\ring.txt', 'Строка символов');
AddStrToTextFile('ring.txt', S1);
AddStrToTextFile('ring.txt', S2);
17.3. Файлы с типом
Файл состоит из любых однотипных компонент. Доступ к данным осуществляется через файловую переменную. В отличие от текстового файла в таком файле допустим прямой доступ к любой записи, причем в рамках открытого файла допустимо как записывать, так и читать записи.
Примеры объявления файловой переменной для файлов с типом:
Var
F1: File of String[45];
F2: File of Real;
F3: File of tRecord24;
После каждого чтения или вывода записи указатель автоматически устанавливается на следующую запись.
17.3.1. Процедуры и функции для работы с типизированным файлом
Procedure AssignFile( f: File of Type; FileName: String);
Связывает файловую переменную f с дисковым файлом FileName.
Procedure Rewrite( f: File of Type);
Создает новый файл и открывает его. Если файл существует, то он уничтожается и создается как новый.
Procedure Reset( f: File of Type);
Открывает существующий файл и устанавливает указатель на первую запись. При отсутствии файла возникает ошибка ввода/вывода.
Procedure Read( f: File of Type[; v1, v2, …,vN]);
Читает записи из файла и заносит их в переменные v1, v2, …, vN. Чтение начинается с той записи, на которую установлен указатель. Типы файла и переменных должны быть одинаковы.
Procedure Write( f: File of Type[; v1, v2, …,vN]);
Записывает данные из переменных v1, v2, …, vN в файл. Вывод данных начинается с той записи, на которую установлен указатель. Если указатель установлен на существующую запись, то при выводе она будет замещена новой записью. Если одновременно выводится несколько записей, то будет замещено такое же количество существующих записей. Типы файла и переменных должны быть одинаковы.
Procedure Seek( f: File of Type; N: LongInt);
Перемещает указатель на запись с номером N. Первая запись имеет порядковый номер 0.
Function FilePos( f: File of Type): LongInt;
Возвращает номер записи, на которую установлен указатель.
Procedure CloseFile( f: File of Type);
Закрывает файл.
Function Eof(f: File of Type): boolean;
Возвращает True, если достигнут конец файла.
Function FileSize(f: File of Type): LongInt;
Возвращает количество записей в файле. Например, Seek(f, FileSize(f)) установит указатель в конец файла (после последней записи).
Procedure Truncate(f: File of Type);
Уничтожает (отрубает) конец файла начиная с записи, на которую установлен указатель.
17.4. Файлы без типа
Файл состоит из компонент одинакового размера. Тип данных не имеет значения. Доступ к данным осуществляется через файловую переменную. Как и в файлах с типом, в таком файле допустим прямой доступ к любой записи, причем в рамках открытого файла допустимо как писать, так и читать записи.
Файловая переменная может быть объявлена так:
Var F: File;
После каждого чтения или вывода записи указатель автоматически устанавливается на следующую запись.
Отсутствие типа записи позволяет выполнять обработку файлов различных типов с помощью универсальных процедур и функций.
17.4.1. Процедуры и функции для работы с файлом без типа
Procedure AssignFile( f: File; FileName: String);
Связывает файловую переменную f с дисковым файлом FileName.
Procedure Rewrite( f: File);
Создает новый файл и открывает его. Если файл существует, то он уничтожается и создается как новый.
Procedure Reset( f: File[; Size: Word]);
Открывает существующий файл и устанавливает указатель на первую запись. При отсутствии файла возникает ошибка ввода/вывода. Параметр Size указывает размер записи открываемого файла. При его отсутствии размер записи по умолчанию равен 1.
Procedure BlockRead( f: File; Var Buf; Count: Word[; Var Result: Word]);
Читает из файла Count записей в переменную Buf. Result – реально прочитанное количество записей.
Procedure BlockWrite( f: File; Var Buf; Count: Word[; Var Result: Word]);
Пишет в файл первых Count записей из переменной Buf. Result – реально записанное количество записей.
Procedure Seek( f: File; N: LongInt);
Перемещает указатель на запись с номером N. Первая запись имеет порядковый номер 0.
Function FilePos( f: File): LongInt;
Возвращает номер записи, на которую установлен указатель.
Procedure CloseFile( f: File);
Закрывает файл.
Function Eof(f: File): boolean;
Возвращает True, если достигнут конец файла.
Function FileSize(f: File): LongInt;
Возвращает количество записей в файле. Например, Seek(f, FileSize(f)) установит указатель в конец файла (после последней записи).
Procedure Truncate(f: File of Type);
Уничтожает (отрубает) конец файла начиная с записи, на которую установлен указатель.
Язык Object Pascal не накладывает никаких ограничений на длину записи (теоретически она может иметь размер до 2 Гб).
Пример описания и обращения к функции ReadFromFile, читающей из файла nF в позиции Pos запись r размером Sz.
function ReadFromFile(nF: String; Pos: Word; Var r; Sz: Word): boolean;
Var
g: File;
Recs, ReadReal: Integer;
RecRead: boolean;
Begin
Assign(g, nF);
Recs:= FileSize(g) div Sz; {количество записей в файле}
RecRead:= (Pos < Recs); {запись с номером Pos есть ?}
if RecRead then begin {если запись есть}
Reset(g, Sz); {открыть файл}
try
Seek(g, Pos); {установить указатель на запись}
BlockRead(g, r, 1, ReadReal); {прочитать запись}
RecRead:= (ReadReal = 1); {прочитано успешно ?}
finally
Close(g); {закрыть файл}
end;
end;
Result:= RecRead;
end {ReadFromFile};
…
Type
tStud = Record
Fio: String [60];
Curs: byte;
Stipendiya, Room: boolean;
End;
Var Stud: tStud;
…
if ReadFromFile('base2.ff1', 12, Stud, SizeOf(Stud))
then Writeln('Запись из 12-й позиции прочитана');
Приведем еще пример. В директории 'c:\Bases\SdudBase' находится файл 'AllStuds.bs', в котором хранятся данные о студентах в виде записей типа
Type
TStud = Record {студент}
Fio: String[50]; {'Фамилия Имя Отчество'}
Born: byte; {Год рождения, например, 1979}
Faculty: String[4]; {Факультет, например, 'МТФ'}
Group: String[8]; {Группа, например, 'МТ 17-2'}
End;
Ниже приведена универсальная процедура, которая копирует из этого файла в другой файл данные только о тех студентах, которые имеют заданный год рождения:
Procedure StudsCopy(nF1, nF2: ShortString; BornYear: byte;
Var Count: Word; Var: Ind: ShortInt);
{nF1 – файл-источник, nF2 – файл-приёмник,
BornYear – требуемый год рождения,
Count – скопировано записей,
Ind – индикатор контроля:
0 – нормально, 1 – было неверное чтение, была неверная запись}
Var
g: tStud;
K, Sz, i,j: Word;
f1, f2: File;
Begin
Count:= 0; {инициализация счетчика}
Ind:=0; {изначально предполагаем нормальный процесс, иначе Ind изменим}
Sz:= SizeOf(g); {размер одной записи}
K:= KdnFileSize(nF1, Sz); {количество записей в файле-источнике}
If (K > 0) then {если в файле-источнике есть записи }
Begin
Assign(f1, nF1); {файл-источник связываем переменной f1}
Reset(f,Sz); {открываем файл-источник с записями размера Sz}
Assign(f2, nF2); {файл-приёмник связываем переменной f2 }
Rewrite(f2,Sz); {создаем новый файл-приёмник под записи размера Sz}
try
For j:=1 to K do
Begin
BlockRead(f1, g, 1, i); {чтение записи}
Case i of
1: {запись прочитана}
if (g.Born = BornYear) then { студент имеет требуемый год рождения}
begin
BlockWrite(f2, g, 1, i); {запись в файл-приёмник}
If (i > 0) then Inc(Count) {если записано правильно}
else
begin Ind:= 1; Break; End; {записано неверно, сразу выход из цикла}
end; {if}
0: begin Ind:= -1; Break; end; {запись не прочитана, сразу выход из цикла}
end; {Case}
end; {цикла For}
finally
CloseFile(f1); {закрываем файл-источник}
CloseFile(f2); {закрываем файл-приёмник}
end; {блока try – finally – end}
End {If };
End {StudsCopy};
Операторы, реализующие копирование требуемых данных в файл '1979.bs':
StudsCopy ('AllStuds.bs', '1979.bs', 1979, Count1979, Ind1979);
Case Ind1979 of
-1: Writeln('Зафиксирована ошибка чтения');
1: Writeln('Зафиксирована ошибка записи');
0: Writeln('Процесс прошел нормально');
end; {Case}
Writeln('Скопировано записей: ' + IntToStr(Count1979));
В этом примере использована внешняя процедура KdnFileSize {количество записей в файле }. Приведем ее текст:
function KdnFileSize(nF: ShortString, Siz: Word): LongInt;
{nF – имя файла, Siz – размер одной записи }
Var
F: File;
L: LongInt;
Begin
L:=0;
If FileExists(nF) then
begin
Assign(f, nF);
Reset(f,1);
L:= SizeOf(f);
If not (L mod Siz = 0) then Writeln('Файл ' + nF + имеет другой тип');
L:= L div Siz;
CloseFile(f);
End;
Result:= L;
End;
17.5. Процедуры и функции для работы с файлами
Эти подпрограммы предназначены для работы с файлами, папками (директориями) и дисками.
Procedure ChDir(Dir: String);
Делает папку Dir текущей. Пример: ChDir('c:\');
Procedure GetDir(D: Byte; Var Dir: String);
Возвращает текущую папку на заданном устройстве. (D= 0 – текущий диск, 1 – диск А, 2 – диск B и т.д.). Пример: GetDir(0, s);
Procedure RmDir(Dir: String);
Уничтожает заданную папку. Папка не должна содержать вложенных папок или файлов. Пример: RmDir('Folder66');
Procedure Erase(f);
Удаляет файл, связанный с файловой переменной f. Файл должен быть закрыт.
Procedure Rename(f, FileName: String);
Переименовывает файл, связанный с файловой переменной f. Файл должен быть закрыт. Пример: Rename(g, 'studs.txt');
Function DiskFree(D: byte): LongInt;
Возвращает количество свободной памяти в байтах на устройстве D. Код драйвера задается так же, как в процедуре GetDir. Если код указан неверно, то возвращает -1.
Function DiskSize(D: byte): LongInt;
Возвращает количество свободной памяти в байтах на устройстве D. Код драйвера задается так же, как в процедуре GetDir. Если код указан неверно, то возвращает -1.