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

       

Введение


В этой главе будут рассмотрены основные примитивы для работы с файлами, предоставляемые системой UNIX. Эти примитивы состоят из небольшого набора системных вызовов, которые обеспечивают прямой доступ к средствам ввода/вывода, обеспечиваемым ядром UNIX. Они образуют строительные блоки для всего ввода/вывода в системе UNIX, и многие другие механизмы доступа к файлам в конечном счете основаны на них. Названия этих примитивов приведены в табл. 2.1. Дублирование функций, выполняемых различными вызовами, соответствует эволюции UNIX в течение последнего десятилетия.

Типичная программа UNIX вызывает для инициализации файла вызов fdopen (или fdcreat), а затем использует вызовы fdread, fdwrite или fdseek для работы с данными в файле. Если файл больше не нужен программе, она может вызвать fdclose, показывая, что работа с файлом завершена. Наконец, если пользователю больше не нужен файл, его можно удалить из системы при помощи вызова unlink.

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

Таблица 2.1. Примитивы UNIX

Имя

Функция

fdopen



Открывает файл для чтения или записи либо создает пустой файл

fdcreat

Создает пустой файл

fdclose

Закрывает открытый файл

fdread

Считывает информацию из файла

fdwrite

Записывает информацию в файл

fdseek

Перемещается в заданную позицию в файле

unlink

Удаляет файл

fcntl

Управляет связанными с файлом атрибутами

(* элементарный пример                   *)

uses linux;

var

  fd:integer;

  nread:longint;

  buf:array [0..1024-1] of char;

begin

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

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

  (* Прочитать данные *)

  nread := fdread (fd, buf, 1024);

  (* Закрыть файл *)

  fdclose (fd);




end.

Первый системный вызов программа примера делает в строке

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

Это вызов функции fdopen, он открывает файл data в текущем каталоге. Второй аргумент функции, Open_RDONLY, является целочисленной константой, определенной в модуле linux. Это значение указывает на то, что файл должен быть открыт в режиме только для чтения (read only). Другими словами, программа сможет только читать содержимое файла и не изменит файл, записав в него какие-либо данные.

Результат вызова fdopen крайне важен, в данном примере он помещается в переменную fd. Если вызов fdopen был успешным, то переменная fd

будет содержать так называемый дескриптор файла (file descriptor) – неотрицательное целое число, значение которого определяется системой. Оно определяет открытый файл при передаче его в качестве параметра другим примитивам доступа к файлам, таким как fdread, fdwrite, fdseek и fdclose. Если вызов fdopen завершается неудачей, то он возвращает значение -1 (большинство системных вызовов возвращает это значение в случае ошибки). В реальной программе нужно выполнять проверку возвращаемого значения и в случае возникновения ошибки предпринимать соответствующие действия.

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

nread := fdread (fd, buf, 1024);

Этот вызов требует считать 1024 символа из файла с идентификатором fd, если это возможно, и поместить их с символьный массив buf. Возвращаемое значение nread дает число считанных символов, которое в нормальной ситуации должно быть равно 1024, но может быть и меньше, если длина файла оказалась меньше 1024 байт. Так же, как и fdopen, вызов fdread возвращает в случае ошибки значение -1.

Переменная nread имеет тип longint, определенный в модуле linux.

Этот оператор демонстрирует еще один важный момент: примитивы доступа к файлам имеют дело с простыми линейными последовательностями символов или байтов. Вызов fdread, например, не будет выполнять никаких полезных преобразований типа перевода символьного представления целого числа в форму, используемую для внутреннего представления целых чисел. Не нужно путать системные вызовы fdread и fdwrite с операторами более высокого уровня в таких языках, как Fortran или Pascal. Системный вызов fdread типичен для философии, лежащей в основе интерфейса системных вызовов: он выполняет одну простую функцию и представляет собой строительный блок, с помощью которого могут быть реализованы другие возможности.

В конце примера файл закрывается:

fdclose(fd);

Этот вызов сообщает системе, что программа закончила работу с файлом, связанным с идентификатором fd. Легко увидеть, что вызов fdclose противоположен вызову fdopen. В действительности, так как программа на этом завершает работу, вызов fdclose не является необходимым, поскольку все открытые файлы автоматически закрываются при завершении процесса. Тем не менее обязательное использование вызова fdclose считается хорошей практикой.

Этот короткий пример должен дать представление о примитивах UNIX для доступа к файлам. Теперь каждый из этих примитивов будет рассмотрен более подробно.


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