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

Более характерным для Pascal являются типизированные файлы, или файлы произвольного доступа. Основным свойством этих файлов является то, что их структура данных представляет собой последовательность компонентов одного типа. Описывают подобный файл словосочетанием file of с последующим указанием типа компонентов файла, число которых (длина файла) не фиксируется:

var имя_файла : file of тип_компонентов

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

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

Чтобы можно было работать с типизированным файлом, необходимо, как и для текстовых файлов, сначала связать имя файловой переменной с внешним именем файла (оператор Assign). Затем нужно открыть его (используются операторы Reset и Rewrite, но не Append). Операторы Reset и Rewrite открывают файл и для чтения, и для записи (а не только для чтения или только для записи, как при использовании текстовых файлов). Отличие их в том, что оператор Reset открывает только существующий файл (если такого файла нет, будет сгенерирована ошибка времени выполнения). С другой стороны, оператор Rewrite создает новый файл (если файл с таким именем уже имеется, то он будет уничтожен и создан заново). При открытии файла с ним связывается текущий указатель файла, который позиционируется на его первый элемент. Оперировать можно только тем элементом файла, на который ссылается указатель файла. При чтении или записи элемента файла происходит автоматическое перемещение указателя на следующий элемент. Чтение из типизированного файла производится оператором Read (но не ReadLn), а запись в него — оператором Write (но не WriteLn). Однако следует помнить, что в списке вывода оператора Write могут быть только переменные. Типы элементов файла и типы переменных в списках ввода-вывода должны быть согласуемы по присваиванию. Элементами типизированных файлов могут быть числовые, символьные, булевы, строковые значения, массивы, записи, но не файлы или структуры с файловыми элементами.

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

Например, если переменная k имеет тип LongInt, а f – файловая переменная типизированного файла, то оператор k := FileSize(f), записывает в переменную k размер файла f.

Элементы типизированного файла нумеруются с нуля (порядковый номер последнего элемента файла на единицу меньше размера файла). Чтобы узнать, на каком элементе располагается указатель файла, используют функцию FilePos:

Текущим положением указателя можно управлять, для чего служит процедура Seek , которая использует следующий синтаксис:

Второй параметр (тип LongInt ) задает номер элемента (отсчет от 0), на который должен переместиться указатель файла. Рассмотрим несколько примеров.

Перейти к пятому (фактически шестому) элементу файла f :

Перейти к предыдущему элементу:

Перейти в конец файла:

Как и для текстовых файлов, можно использовать функцию Eof(имя_файла), которая возвращает значение True, если текущий указатель расположен на признаке конца файла (т. е. при выполнения равенства FilePos(имя_файла) = FileSize(имя_файла)).

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

Текстовые файлы могут быть созданы текстовым редактором. Однако типизированные файлы создаются в результате работы какой-либо программы.

Пример записи данных в типизированный файл:

Пример последовательного доступа к типизированному файлу:

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

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

Эти файлы в отличие от уже рассмотренных не имеют строго определенного типа.

Нетипизированный файл рассматривается в Паскале как совокупность символов или байтов. Представление char или byte не играет никакой роли, важен лишь объем занимаемых данных.

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

Для определения в программе нетипизированного файла служит зарезервированное слово file:

Читайте также:  Разница между live и life
Var
MyFile : file;

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

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

Для таких файлов самым важным параметром является длина записи в байтах. Открытие нетипизированного файла с длиной записи в 1 байт можно выполнить следующим образом:

rewrite(MyFile, 1) или reset(MyFile, 1)

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

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

rewrite(MyFile) или reset(MyFile)

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

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

Во-первых, для обеспечения максимальной скорости обмена данными следует задавать длину, которая была бы кратна длине физического сектора дискового носителя информации (512 байт).

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

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

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

assign (МуFilе, ‘с:МуDirectory
esult.dat’) — процедура связывания логической файловой переменной МуFilе с конкретным физическим файлом на дисковом носителе информации;

closе (МуFilе) — процедура, закрывающая открытый файл;

rewrite (МуFilе) — процедура, создающая новый файл и открывающая его для записи или чтения; эта процедура имеет дополнительный параметр при работе с нетипизированными файлами, который будет рассмотрен позднее;

reset (МуFilе) — процедура, открывающая существующий файл данных; эта процедура имеет дополнительный параметр при работе с нетипизированными файлами, который будет рассмотрен позднее;

eof (МуFilе) — логическая функция, проверяющая, достигнут ли конец файла;

seek (МуFilе, n) — процедура, позволяющая явно изменить значение текущего указателя файла, установив его на элемент с номером n;

filesize(МуFilе) — функция, возвращающая позицию указателя по файлу; нумерация начинается с нуля;

filepos (МуFilе) — функция, возвращающая количество элементов файла;

rename(МуFilе, FileName) — процедура, позволяющая переименовать существующий файл;

truncate(МуFilе) — процедура, позволяющая удалить часть существующего файла, начиная с текущей позиции;

erase(МуFilе) — процедура, стирающая указанный файл,

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

blockread(Var F : file; Var Buf; Kolblocks : word; result : word);

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

Параметр Buf представляет любую переменную, которая будет участвовать в обмене данными с дисками. Эту переменную нужно описать в программе так, чтобы ее размер не был меньше размера записи, установленного в параметрах rewrite или reset (как правило, для этих целей используется некоторый массив).

Параметр Kolblocks задает число считываемых блоков, которые должны быть прочитаны за одно обращение к диску.

Параметр result является необязательным и содержит после вызова процедуры число действительно считанных записей.

Использование параметра result подсказывает, что число считанных блоков может быть меньше, чем задано параметром Kolblocks. Если result указан при вызове, то ошибки ввода-вывода в такой ситуации не произойдет. Для отслеживания этой и других ошибок чтения можно использовать опции <$I->, <$I+>и функцию IOresult.

Кроме того, что переменная F должна быть описана как нетипизированный файл, она должна быть связана с конкретным физическим диском процедурой assign. Файл должен быть открыт процедурой reset.

Читайте также:  Asus zenfone 2 ze551ml 32gb gold
blockwrite(Var F : file; Var Buf; Kolblocks : word; result : word);

Процедура предназначена для быстрой передачи в файл F определенного числа записей из переменной Buf. Все параметры процедуры blockwrite аналогичны параметрам процедуры blockread. Разница лишь в том, что файл должне быть подготовлен для записи процедурой rewrite. Содержимое переменной Buf целиком помещается в файл, начиная с текущей записи.

Обе процедуры выполняют операции ввода-вывода блоками. Объем блока в байтах определяется по формуле:

Объем = Kolblocks * recSize,

где recSize — размер записи файла, заданный при его открытии. Суммарный объем разового обмена не должен превышать 64 Кбайт. Помимо скорости передачи данных преимущество этих процедур заключается в возможности пользователя самостоятельно определять размер буфера для файловых операций. Эта возможность играет значительную роль в тех задачах, где необходимо жесткое планирование ресурсов. Программист должен позаботиться о том, чтобы длина внутреннего представления переменной Buf была достаточной для размещения всех байт при чтении информации с диска.

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

Если при чтении указана переменная Buf недостаточной длины или если в процессе записи на диск не окажется нужного свободного пространства, то произойдет следующее. Если последний параметр result в этих вызовах не задан, то возникает ошибка ввода-вывода; если параметр result задан, то ошибка не будет зафиксирована, а после выполнения процедуры его значение не будет совпадать с значением параметра Kolblocks. Последнее обстоятельство можно проверить, сравнив два указанных значения.

После завершения процедуры указатель смещается на result записей.

Рассмотрите примеры простых задач.

Задача 1. Составить программу, которая создает нетипизированный файл из 100 чисел и выводит на экран k-ый элемент.

Program Netipiz1;
Uses
Crt;
Type
FileType = file;
Var
f : FileType;
P, B, k : byte;
Begin
ClrScr;
assign(F, ‘MyFile’);
rewrite(F,1);
Randomize;
for k := 1 to 100 do
begin
P := Random(100);
blockwrite(F, P, 1);
end;
close(F);
reset(F,1);
for k := 1 to 100 do
begin
blockread(F, P, 1);
write(p,’ ‘);
end;
write(‘Введите номер нужного элемента ‘);
readln(k);
Seek(F, k-1);
blockread(F, P, 1);
writeln(k,’-ий элемент файла равен ‘, P);
close(F);
End.

Задача 2. Составить программу, которая создает копию элементов нетипизированного файла f и помещает в файл g.

Program Netipiz2;
Uses
Crt;
Var
f, g : file;
Stroka1, sб Stroka2 : string;
Begin
ClrScr;
write(‘Введите имя исходного файла’);
read(Stroka1);
assign(f, Stroka1);
rewrite(f,1);
write(‘Введите содержимое файла ‘);
repeat
readln(s);
blockwrite(f, s, 1);
until readKey = #27;
close(f);
reset(f,1);
write(‘Введите имя конечного файла’);
read(Stroka2);
assign(g, Stroka2);
rewrite(g,1);
while not Eof(f) do
begin
blockread(f, s, 1);
blockwrite(g, s, 1);
end;
close(f);
close(g);
write(‘Содержимое конечного файла:’);
while not Eof(g) do
begin
blockread(g, s, 1);
write(s);
end;
readln;
End.

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

Program Netipiz3;
Uses
Crt;
Var
f : file;
i, k, s : integer;
Mas : Array [1..10] of byte;
Begin
ClrScr;
Randomize;
for i := 1 to 10 do
Mas[i] := Random(10);
assign(f, ‘file.dat’);
rewrite(f,1);
blockwrite(f, Mas, 10);
close(f);
reset(f,1);
while not Eof(f) do
begin
blockread(f, k, 1);
s:= s+k;
Inc(i);
end;
close(f);
write(s/i:5:2);
readln;
End.

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

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

При инициации нетипизированного файла процедурами RESET или REWRITE можно указать длину записи нетипизированного файла в байтах. Например, так:

Var

Begin

assign (f, ‘myfile.dat’);

End.

Длина записи нетипизированного файла указывается вторым параметром при обращении к процедурам RESET или REWRITE, в качестве которого может использоваться выражение типа WORD. Если длина записи не указана, она принимается равной 128 байтам.

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

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

Читайте также:  В какой соцсети можно познакомиться

Здесь — буфер: имя переменной, которая будет участвовать в обмене данными с дисками;

— количество записей, которые должны быть прочитаны или записаны за одно обращение к диску;

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

За одно обращение к процедурам может быть передано до N*RECS байт, где RECS — длина записи нетипизированного файла. Передача идет, начиная с первого байта переменной . Программист должен позаботится о том, чтобы длина внутреннего представления переменной была достаточной для перемещения всех N*RECS байт при чтении информации с диска. Если при чтении указана переменная недостаточной длины или если в процессе записи на диск не окажется нужного свободного пространства, возникнет ошибка ввода-вывода, которую можно заблокировать, указав необязательный параметр (переменная типа WORD).

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

Тема № 11: «Процедуры и функции»

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

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

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

Любая подпрограмма должна быть описана до того, как она будет вызвана в программе или в другой подпрограмме Все переменные, которые использует подпрограмма, могут быть либо глобальными, т.е. объявленные в основной программе и доступные как программе, так и всем ее подпрограммам, либо локальными, т.е. объявленные внутри подпрограммы и доступные только ей собой. Обмен данными между основной программой и подпрограммой может осуществляться только с помощью глобальных переменных.

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

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

За заголовком следуют такие же разделы, что и в основной программе.

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

параметры — значения — эти параметры в основной программе подпрограммой не изменяются;

параметры — переменные— эти параметры подпрограмма может изменить в основной программе;

параметры — процедуры и параметры — функции.

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

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

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

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

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

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

a,b, Sum, Sum_Number: Integer;

Procedure Summ1 (Var Sum: Integer; a,b: integer);

Function Summ2( a,b: integer): integer;