Скачиваний:
56
Добавлен:
08.01.2014
Размер:
2.6 Mб
Скачать

Описание

uses stdio;

function puts(str:pchar):integer;

function fputs(str:pchar; outf:pfile):integer;

Процедура puts записывает все символы (кроме завершающего нулевого символа) из строки str на стандартный вывод (stdout). Процедура fputs записывает строку str в поток outf. Для обеспечения совместимости со старыми версиями системы процедура puts добавляет в конце символ перевода строки, процедура же fputs не делает этого. Обе функции возвращают в случае ошибки значение EOF.

Следующий вызов процедуры puts приводит к выводу сообщения Hello, world на стандартный вывод, при этом автоматически добавляется символ перевода строки newline:

puts('Hello, world');

11.9. Ввод и вывод бинарных данных: процедуры freadи fwrite Описание

uses stdio;

function fread(buffer:pointer; size, nitems:longint; inf:pfile):longint;

function fwrite(buffer:pointer; size,nitems:longint; outf:pfile):longint;

Эти две полезные процедуры обеспечивают ввод и вывод произвольных нетекстовых данных. Процедура fread считывает nitems объектов данных из входного файла, соответствующего потоку inf. Считанные байты будут помещены в массив buffer. Каждый считанный объект представляется последовательностью байтов длины size. Возвращаемое значение дает число успешно считанных объектов.

Процедура fwrite является точной противоположностью процедуры fread. Она записывает данные из массива buffer в поток outf. Массив buffer содержит nitems объектов, размер которых равен size. Возвращаемое процедурой значение дает число успешно записанных объектов.

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

Следующий пример показывает, как все это работает. В нем используется шаблон структуры dict_elem. Экземпляр этой структуры может представлять собой часть записи простой базы данных. Используя терминологию баз данных, структура dict_elem представляет собой запись, или атрибут, базы данных. Мы поместили определение структуры dict_elem в заголовочный файл dict.inc, который выглядит следующим образом:

(* dict.inc - заголовочный файл для writedict и readdict *)

uses stdio;

(* Структура dict_elem элемент данных *)

(* (соответствует полю базы данных) *)

type dict_elem=record

d_name:array [0..14] of char; (* имя элемента словаря *)

d_start:integer; (* начальное положение записи *)

d_length:integer; (* длина поля *)

d_type:integer; (* обозначает тип данных *)

end;

pdict_elem=^dict_elem;

const

ERROR=-1;

SUCCESS=0;

He вдаваясь в смысл элементов структуры, введем две процедуры writedict и readdict, которые соответственно выполняют запись и чтение массива структур dict_elem. Файлы, создаваемые при помощи этих двух процедур, можно рассматривать как простые словари данных для записей в базе данных.

Процедура writedict имеет два параметра, имя входного файла и адрес массива структур dict_elem. Предполагается, что этот список заканчивается первой структурой массива, в которой элемент d_length равен нулю.

{$i dict.inc}

function writedict (const dictname:pchar; elist:pdict_elem):integer;

var

j:integer;

outf:pfile;

begin

(* Открыть входной файл *)

outf := fopen (dictname, 'w');

if outf = nil then

begin

writedict:=ERROR;

exit;

end;

(* Вычислить размер массива *)

j:=0;

while elist[j].d_length <> 0 do

inc(j);

(* Записать список структур dict_elem *)

if fwrite (elist, sizeof (dict_elem), j, outf) < j then

begin

fclose (outf);

writedict:=ERROR;

exit;

end;

fclose (outf);

writedict:=SUCCESS;

end;

Обратите внимание на использование sizeof(dict_elem) для сообщения процедуре fwrite размера структуры dict_elem в байтах.

Процедура readdict использует процедуру fread для считывания списка структур из файла. Она имеет три параметра: указатель на имя файла словаря indictname, указатель inlist на массив структур dict_elem, в который будет загружен список структур из файла, и размер массива maxlength.

function readdict (const indictname:pchar;inlist:pdict_elem;

maxlength:integer):pdict_elem;

var

i:integer;

inf:pfile;

begin

(* Открыть входной файл *)

inf := fopen (indictname, 'r');

if inf = nil then

begin

readdict:=nil;

exit;

end;

(* Считать структуры dict_elem из файла *)

for i:=0 to maxlength - 1 do

if fread (@inlist[i], sizeof (dict_elem), 1, inf) < 1 then

break;

fclose (inf);

(* Обозначить конец списка *)

inlist[i].d_length := 0;

(* Вернуть начало списка *)

readdict:=inlist;

end;

const

delem1:array [0..1] of dict_elem=(

(d_name:('d','n','a','m','e', #0,#0,#0,#0,#0,#0,#0,#0,#0,#0);

d_start:2; d_length:15; d_type:3),

(d_name:(#0, #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, #0)

d_start:0; d_length:0; d_type:0)

);

var

delem2:array [0..1] of dict_elem;

begin

printf ('delem1: d_name=%s, d_start=%d, d_length=%d, d_type=%d'#$a,

[pchar(delem1[0].d_name), delem1[0].d_start, delem1[0].d_length,

delem1[0].d_type]);

writedict ('dictionary', @delem1[0]);

if readdict ('dictionary', @delem2[0], 2)<>nil then

printf ('delem2: d_name=%s, d_start=%d, d_length=%d, d_type=%d'#$a,

[pchar(delem2[0].d_name), delem2[0].d_start, delem2[0].d_length,

delem2[0].d_type]);

end.

И снова обратите внимание на приведение типа и использование конструкции sizeof.

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

И последний момент: можно было бы получить практически тот же результат, напрямую используя вызовы fdread или fdwrite, например:

fdwrite(fd, ptr, sizeof(dict_elem));

Основное преимущество версии, основанной на стандартной библиотеке ввода/вывода, снова заключается в ее лучшей эффективности. Данные при этом будут читаться и записываться большими блоками, независимо от размера структуры dict_elem.

Упражнение 11.6. Представленные версии процедур writedict и readdict работают с файлами словаря, которые могут содержать только один тип записей. Измените их так, чтобы в одном файле можно было хранить информацию о нескольких типах записей. Другими словами, нужно, чтобы файл словаря мог содержать несколько независимых именованных списков структур dict_elem. (Совет: включите в начало файла «заголовок»; содержащий информацию о числе записей и типе полей.)

Соседние файлы в папке Полищук, Семериков. Системное программирование в UNIX средствами Free Pascal