[ Страница назад | Страница вперед | Содержание | Индекс | Библиотека | Юридическая информация | Поиск ]

Программирование: Разработка и отладка программ


Работа с дескрипторами файлов

Дескриптор файла - это целое число без знака, с помощью которого процесс обращается к открытому файлу. В каждом процессе может быть выделено до двух тысяч дескрипторов. Они создаются при выполнении функций open, pipe, creat и fcntl. Обычно каждый процесс работает с уникальным набором дескрипторов. Однако эти же дескрипторы могут применяться и дочерними процессами, созданными с помощью функции fork. Кроме того, дескрипторы можно скопировать с помощью функций fcntl, dup и dup2.

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

Таблица открытых файлов и таблица дескрипторов файлов

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

Структура Назначение и содержание
таблица дескрипторов файлов Преобразует индексы таблицы (дескрипторы файлов) в указатели на открытые файлы. Для каждого процесса в области u_block создается своя собственная таблица дескрипторов. Каждая запись такой таблицы содержит два поля: поле флагов и указатель на файл. Ниже описана структура таблицы дескрипторов:

struct ufd
{
        struct file *fp;
        int flags;
}u_ufd[OPEN_MAX]

Функция fcntl позволяет установить флаг FD_CLOEXEC в записи таблицы дескрипторов. Функция dup копирует запись о дескрипторе файла в другую строку этой же таблицы. При выполнении функции fork для дочернего процесса создается копия всей таблицы дескрипторов файлов.

Таблица открытых файлов Содержит записи с информацией обо всех открытых файлах. Два наиболее важных поля в записях этой таблицы - это текущее положение указателя в файле, на который ссылаются все операции чтения и записи, а также режим открытия файла (O_RDONLY, O_WRONLY или O_RDWR).

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

Управление дескрипторами файлов

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

Несколько обращений к файлу может возникнуть в следующих ситуациях:

Совместная работа с открытыми файлами

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

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

Копирование дескрипторов файлов

Существует три способа копирования дескрипторов файлов: с помощью функций dup и dup2, а также с помощью функций fork и fcntl.

Функции dup и dup2


dup Создает копию дескриптора файла

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

dup2 Находит запрошенный дескриптор и закрывает связанный с ним файл, если он открыт.

Функция dup2 позволяет указать конкретную запись таблицы, в которую должен быть скопирован дескриптор.

Функция fork


fork Создает дочерний процесс, который наследует дескрипторы файлов родительского процесса. После этого дочерний процесс запускает новый процесс. Унаследованные дескрипторы с флагом Закрыть при exec, установленным с помощью fcntl, будут закрыты.

Функция fcntl


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

Функция fcntl позволяет выполнять следующие операции над дескрипторами:

  • Копировать дескриптор файла (аналогично функции dup).
  • Получать или устанавливать значение флага Закрыть при exec.
  • Выключать режим объединения дескрипторов в блоки.
  • Включать режим добавления данных в конец файла (O_APPEND).
  • Включать отправку процессам сигнала о разрешении ввода-вывода.
  • Устанавливать и получать ИД процесса или группы процессов для отправки SIGIO.
  • Закрывать все дескрипторы файлов.

Стандартные дескрипторы файлов

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

0 Стандартный ввод.
1 Стандартный вывод.
2 Стандартный вывод сообщений об ошибках.

Перечисленные дескрипторы файлов связаны с терминалом. Это означает, что при чтении данных из файла с дескриптором 0 программа получает ввод с терминала, а при записи данных в файлы с дескрипторами 1 и 2 они выводятся на терминал. При открытии других файлов дескрипторы присваиваются в порядке возрастания.

Если ввод-вывод перенаправляется с помощью операторов < (знак меньше) или > (знак больше), то стандартные дескрипторы связываются с другими файлами. Например, при выполнении команды:

prog < FileX > FileY

стандартные дескрипторы файлов 0 и 1 связываются с указанными файлами. В данном примере дескриптор 0 будет связан с файлом FileX, а дескриптор 1 - с файлом FileY. Дескриптор 2 не будет изменен. Программе достаточно знать, что дескриптор 0 представляет файл ввода, а дескрипторы 1 и 2 - файлы вывода. Информация о том, с какими конкретно файлами связаны эти дескрипторы, ей не нужна.

В следующем примере программы продемонстрировано перенаправление стандартного вывода:

#include <fcntl.h>
#include <stdio.h>
 
void redirect_stdout(char *);
 
main()
{
       printf("Hello world\n");       /* печать в стандартный
                                         вывод */
       fflush(stdout);
       redirect_stdout("foo");        /*перенаправление стандартного вывода*/
       printf("Hello to you too, foo\n");
                                      /*печать в файл foo */
       fflush(stdout);
}

void
redirect_stdout(char *filename)
{
        int      fd;
        if ((fd = open(filename,O_CREAT|O_WRONLY,0666)) < 0)
                                        /*открытие нового файла*/
        {
                perror(filename);
                exit(1);
        }
        close(1);                       /*закрытие стандартного*/
                                          вывода */
        if (dup(fd) !=1)                /*присвоение новому дескриптору
                                        *значения 1*/
        {
                fprintf(stderr,"Unexpected dup failure\n");
                exit(1);
        }
        close(fd);                       /*закрытие ненужного*/
                                         * исходного fd*/
}

Дескриптор 2 также можно присвоить другому файлу, однако это редко применяется на практике.

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

Ограничение на число дескрипторов файлов

Максимальное число дескрипторов, которое может использоваться в одном процессе, ограничено. Значение по умолчанию устанавливается в файле /etc/security/limits и обычно равно 2000 (для совместимости с предыдущими выпусками). Для изменения ограничения можно воспользоваться командой ulimit или функцией setrlimit. Максимальное число определяется константой OPEN_MAX.

Связанная информация

Глава 5, Файловые системы и каталоги

Работа с i-узлами JFS

Создание и удаление файлов

Особые файлы - Обзор

Функции fcntl, dup, dup2, lseek, open, openx и create


[ Страница назад | Страница вперед | Содержание | Индекс | Библиотека | Юридическая информация | Поиск ]