While FilePos(F)<>FileSize(F) do
Begin
Read(F,People);
People.Money:= People.Money*2;
Seek(F, FilePos(F)-1);
Write(F,People);
end;
FINALLY
CloseFile(F);
END;
Несколько сложнее обстоят дела с удалением из типизированного файла ненужного элемента. Однако при должной сноровке и эта задача вполне разрешима. Предположим, что за какую-то провинность (например, несанкционированное повышение зарплаты всем сотрудникам) из списка надо вычеркнуть бухгалтера Петрова. Для реализации этой карательной акции нам потребуются две файловые переменные: Source и Receptor. С помощью Source мы присоединимся к исходному файлу и просто переберем все его элементы, проверяя при этом, не является ли текущий элемент записью о нашалившем счетоводе Петрове. Вторая файловая переменная Receptor нацелена на создание файла-получателя. В этот файл мы переносим все элементы исходного файла, успешно избежавшие фильтрации (с фамилиями, отличными от «Петров»).
var People: TPeople;
Source, Receptor : File Of TPeople;
Begin
AssignFile(Source,'c:\People.dat');
TRY
Rename(Source, 'c:\~People.dat'); // переименовываем старый файл
Reset(Source); // подключаемся к старому файлу
AssignFile(Receptor,'c:\People.dat');
Rewrite(Receptor);
while FilePos(Source)<>FileSize(Source) do // цикл перебора элементов
// старого файла
Begin
Read(Source,People);
if People.SurName<>'Петров' thenWrite(Receptor,People);
end;
FINALLY
CloseFile(Source);
Erase(Source); //удаляем старый файл
CloseFile(Receptor);
END;
End.
В рассмотренном листинге мы использовали еще две новые процедуры. Первая из них предназначена для переименования файла F. Новое имя надо указать в параметре NewName.
procedure Rename(var F; Newname: string);
Для удаления файла нам понадобится метод Erase().
procedure Erase(var F);
Прежде чем удалить файл, определенный в файловой переменной F, обязательно закройте его, вызвав метод CloseFile().
Если типизированный файл включает сотни (и более) записей, предложенный выше алгоритм «борьбы с лишними сотрудниками» становится весьма неэффективным, в особенности если за один сеанс работы с файлом удаляет ся несколько записей. Ведь мы ради каждой удаляемой строки вынуждены заново перезаписывать достаточно большой файл, а это весьма ресурсоемкая и, главное, продолжительная операция.
В таких случаях программисты идут на хитрость: в состав полей записи типизированного файла добавляется еще одно поле логического типа, например Deleted, в котором хранится признак удаления. При поступлении команды на удаление записи вместо реального стирания строки полю Deleted присваивается значение true и запись убирается с экрана. На все это уходят тысячные доли секунды, а реальное удаление строк выполняется (в тайне от всех) в момент закрытия программы.
Весьма похожий алгоритм удаления строк с успехом работает в базах данных dBase и Paradox. Более того, в этих таблицах строки вообще никогда не удаляются, а просто скрываются. Правда, это сопряжено с одним недостатком: файлы таблиц постоянно увеличиваются в размерах. Поэтому изредка их требуется упаковывать с помощью специальных подпрограмм.
Двоичные файлы
Подавляющее большинство файлов, хранящихся на жестких дисках компьютеров, не являются типизированными. С точки зрения языка Pascal они не имеют строгого формата. Точнее говоря, в их формате разбираются только узкоспециальные программы. Например, программы Adobe PageMaker и Microsoft Word (по сути выполняющие аналогичные задачи – редактирование текста) работают с весьма несхожими файлами. Дело в том, что в их файлах помимо текста хранится обширная служебная информация: гарнитура, кегль и цвет шрифта, трекинг, интерлиньяж и многое другое. Разработчики двух разных программных продуктов для каждого из пакетов сформировали свой формат файла и вполне довольны полученными результатами. Возможно, и вы создадите свой тип файла, однако в нашей классификации он все равно будет именоваться двоичным.
Отличие состава базовых операций ввода-вывода, применяемых для нетипизированных файлов, заключается в методах, осуществляющих чтение и запись. Суть отличия от уже известных вам процедур Read() и Write() заключается в том, что чтение и запись производятся блоками.
procedure BlockRead(var F: File; var Buf; Count: Integer [; var AmtTransferred:
Integer]);
procedure BlockWrite(var F: File; var Buf; Count: Integer [; var AmtTransferred:
Integer]);
С первым аргументом F все ясно: это файловая переменная. Второй аргумент Buf служит буфером, в который записываются прочитанные данные или, наоборот, из которой считывается информация для сохранения в файле. Параметр Count определяет, сколько записей планируется считать из файла за одну операцию чтения. Как правило, ему присваивают значение, равное 1. Последний аргумент, AmtTransferred, необязательный. Во время операций чтения из него можно узнать количество записей, реально считанных из файла, а во время осуществления записи в переменной окажется количество записей, внесенных в файл.
Внимательный читатель наверняка уже заинтересовался: «Что мы имеем в виду, когда применяем термин запись при работе с нетипизированным файлом?» Действительно, здесь требуется внести некоторую ясность. Еще раз взгляните на объявление методов BlockRead() и BlockWrite(). В этих процедурах не определен тип аргумента Buf, что так не похоже на строгий язык Pascal. Но каким образом можно определить тип данных для работы с файлом, который по определению нетипизирован? Поэтому в качестве буфера обычно используют обычный байтовый массив:
var Buf : array [0..127] of byte;
Размер массива устанавливается программистом. Вот про этот размер и говорят – размер записи, а сам буфер часто именуют записью. По умолчанию размер буфера назначают равным 128 байт. Если этот размер не устраивает, его можно изменить под свою задачу. Однако при этом надо помнить о втором параметре процедур Reset() и Rewrite(), который определяет размер блока. Если есть необходимость, перечитайте раздел, посвященный текстовым файлам.
Размер записи всегда должен быть кратен размеру файла, с которым собираетесь работать. В противном случае вы столкнетесь с проблемой чтения за пределами файла. Самым универсальным размером записи служит 1 байт, однако такое значение снизит производительность процедур чтения-записи. Как говорится, лучше один раз увидеть. Взгляните на листинг, демонстрирующий способ создания двоичного файла.
program DemoBinFl;
{$APPTYPE CONSOLE}
uses SysUtils;
varF : File;
Buffer : array[0..1023] of byte;
I : integer;
Begin
for i:=0 to SizeOf(Buffer) do Buffer[i]:=RANDOM(255);
AssignFile(F,'c:\binfile.dat');
TRY
Rewrite(F,1024);
BlockWrite(F,Buffer,1);
FINALLY
CloseFile(F);
END;
End.
В качестве буфера используется массив размером 1 Кбайт. Заполнив массив псевдослучайными числами, переносим содержимое его ячеек на жесткий диск.
Следующий листинг демонстрирует процесс чтения из не типизированного файла. Пример рассчитан на то, что размер загружаемого файла кратен 256 байт.
program DemoBinRead;
{$APPTYPE CONSOLE}
{Чтение из двоичного файла}
usesSysUtils;
varF : File;
Buffer: array[0..255] of byte;
i : integer;
Begin
AssignFile(F,'c:\binfile.dat');
TRY
Reset(F,256);
while EOF(F)=False do
Begin
BlockRead(F,Buffer,1);
//прочие операции
end;
FINALLY
CloseFile(F);
END;
End.
Дата добавления: 2016-03-15; просмотров: 743;