Системное программирование в UNIX средствами Free Pascal

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


Достаточно естественно, что программа может последовательно вызывать 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.


Содержание раздела