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

2.1.6. Системный вызовfdread

Системный вызов fdread используется для копирования произвольного числа символов или байтов из файла в буфер. Буфер формально устанавливается как ссылка на бестиповую переменную; это означает, что он может содержать элементы любого типа. Хотя обычно буфер является массивом данных типа char, он также может быть массивом структур, определенных пользователем.

Заметим, что программисты на языке Паскаль часто любят использовать термины «символ» и «байт» как взаимозаменяемые. Байт является единицей памяти, необходимой для хранения символа, и на большинстве машин имеет длину восемь бит. Термин «символ» обычно описывает элемент из набора символов ASCII, который является комбинацией всего из семи бит. Поэтому обычно байт может содержать больше значений, чем число символов ASCII; такая ситуация возникает при работе с двоичными данными. Тип char языка С представляет более общее понятие байта, поэтому название данного типа является не совсем правильным.

Описание

uses linux;

Function fdRead(filedes:longint;var buffer;size:longint):longint;

Первый параметр, filedes, является дескриптором файла, полученным во время предыдущего вызова fdopen или fdcreat. Второй параметр, buffer, – это ссылка на массив или структуру, в которую должны копироваться данные. Во многих случаях в качестве этого параметра будет выступать просто имя массива, например:

var

fd:integer;

nread:longint;

buffer:array [0..SOMEVALUE-1] of char;

(* Дескриптор файла fd получен в результате вызова fdopen *)

.

.

.

nread := fdread(fd, buffer, SOMEVALUE);

Как видно из примера, третьим параметром вызова fdread является положительное число (имеющее тип longint), задающее число байтов, которое требуется считать из файла.

Возвращаемое вызовом fdread число (присваиваемое в примере переменной nread) содержит число байтов, которое было считано в действительности. Обычно это число запрошенных программой байтов, но, как будет показано в дальнейшем, – не всегда, и значение переменной nread может быть меньше. Кроме того, в случае ошибки вызов fdread возвращает значение -1. Это происходит, например, если передать fdread недопустимый дескриптор файла.

Указатель чтения-записи

Достаточно естественно, что программа может последовательно вызывать fdread для просмотра файла. Например, если предположить, что файл foo содержит не менее 1024 символов, то следующий фрагмент кода поместит первые 512 символов из файла foo в массив buf1, а вторые 512 символов – в массив buf2.

var

fd:integer;

n1,n2:longint;

buf1, buf2 : array [0..511] of char;

.

.

.

fd := fdopen('foo', Open_RDONLY);

if fd = -1 then

halt(-1);

n1 := fdread(fd, buf1, 512);

n2 := fdread(fd, buf2, 512);

Система отслеживает текущее положение в файле при помощи объекта, который называется указателем ввода/вывода (read-write pointer), или указателем файла (file pointer). По существу, в этом указателе записано положение очередного байта в файле, который должен быть считан (или записан) следующим для определенного дескриптора файла; следовательно, указатель файла можно себе представить в виде закладки. Его значение отслеживает система, и программисту нет необходимости выделять под него переменную. Произвольный доступ, при котором положение указателя ввода/вывода изменяется явно, может осуществляться при помощи системного вызова fdseek, который описан в разделе 2.1.10. В случае вызова fdread система просто перемещает указатель ввода/вывода вперед на число байтов, считанных в результате данного вызова.

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

Следующая программа count иллюстрирует некоторые из этих моментов:

(* Программа count подсчитывает число символов в файле *)

uses linux;

const

BUFSIZE=512;

var

filedes:integer;

nread:longint;

buffer:array [0..BUFSIZE-1] of byte;

total:longint;

begin

total := 0;

(* Открыть файл 'anotherfile' только для чтения *)

filedes := fdopen ('anotherfile', Open_RDONLY);

if filedes=-1 then

begin

writeln('Ошибка при открытии файла anotherfile');

halt(1);

end;

(* Повторять до конца файла, пока nread не будет равно 0 *)

nread := fdread (filedes, buffer, BUFSIZE);

while nread > 0 do

begin

inc(total,nread); (* увеличить total на nread *)

nread := fdread (filedes, buffer, BUFSIZE);

end;

writeln('Число символов в файле anotherfile: ', total);

fdclose(filedes);

halt(0);

end.

Эта программа будет выполнять чтение из файла anotherfile блоками по 512 байт. После каждого вызова fdread значение переменной total будет увеличиваться на число символов, действительно скопированных в массив buffer. Почему total объявлена как переменная типа longint?

Здесь использовано для числа считываемых за один раз символов значение 512, поскольку система UNIX сконфигурирована таким образом, что наибольшая производительность достигается при перемещении данных блоками, размер которых кратен размеру блока на диске, в этом случае 512. (В действительности размер блока зависит от конкретной системы и может составлять до и более 8 Кбайт.) Тем не менее мы могли бы задавать в вызове fdread произвольное число, в том числе единицу. Введение определенного значения, соответствующего вашей системе, не дает выигрыша в функциональности, а лишь повышает производительность программы, но, как мы увидим в разделе 2.1.9, это улучшение может быть значительным.

Упражнение 2.4. Если вы знаете, как это сделать, перепишите программу count так, чтобы вместо использования постоянного имени файла она принимала его в качестве аргумента командной строки. Проверьте работу программы на небольшом файле, состоящем из нескольких строк.

Упражнение 2.5. Измените программу count так, чтобы она также выводила число слов и строк в файле. Определите слово как знак препинания или алфавитно-цифровую строку, не содержащую пробельных символов, таких как пробел, табуляция или перевод строки. Строкой, конечно же, будет любая последовательность символов, завершающаяся символом перевода строки.

Следующая программа демонстрирует функции fdread и fdtrucate.

Uses linux;

Const Data : string[10] = '12345687890';

Var FD : Longint;

l : longint;

begin

FD:=fdOpen('test.dat',open_wronly or open_creat,octal(666));

if fd>0 then

begin

{ Fill file with data }

for l:=1 to 10 do

if fdWrite (FD,Data[1],10)<>10 then

begin

writeln ('Error when writing !');

halt(1);

end;

fdClose(FD);

FD:=fdOpen('test.dat',open_rdonly);

{ Read data again }

If FD>0 then

begin

For l:=1 to 5 do

if fdRead (FD,Data[1],10)<>10 then

begin

Writeln ('Error when Reading !');

Halt(2);

end;

fdCLose(FD);

{ Truncating file at 60 bytes }

{ For truncating, file must be open or write }

FD:=fdOpen('test.dat',open_wronly,octal(666));

if FD>0 then

begin

if not fdTruncate(FD,60) then

Writeln('Error when truncating !');

fdClose (FD);

end;

end;

end;

end.

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