Когда процесс получает доступ к файлу (что обычно называют
Первые три файловых дескриптора для процессов (0, 1 и 2) имеют стандартное назначение. Первый, 0, известен как стандартный ввод (gets()
и printf()
используют stdin и stdout соответственно, и это соглашение дает возможность командным оболочкам правильно перенаправлять ввод и вывод процессов.
Заголовочный файл
представляет макросы STDIN_FILENO
, STDOUT_FILENO
и STDERR_FILENO
, которые вычисляются как файловые дескрипторы stdin, stdout и stderr соответственно. Использование этих символических имен делает код более читабельным.
Многие из файловых операций, которые манипулируют файловыми узлами inode, доступны в двух формах. Первая форма принимает в качестве аргумента имя файла. Ядро использует этот аргумент для поиска inode файла и выполняет соответствующую операцию над ним (обычно это включает следование символическим ссылкам). Вторая форма принимает файловый дескриптор в качестве аргумента и выполняет операцию над inode, на который он ссылается. Эти два набора системных вызовов используют похожие имена, но системные вызовы, работающие с файловыми дескрипторами, имеют префикс chmod()
изменяет права доступа для файла, ссылка на который осуществляется по имени; fchmod()
устанавливает права доступа к файлу, ссылаясь на него по указанному файловому дескриптору.
Чтобы меньше тратить слов, мы представим обе версии системных вызовов, если они существуют, а обсуждать будет только первую из их (та, которая использует имена файлов).
11.2.2. Закрытие файлов
Одной из операций, которые одинаковы для файлов всех типов, является закрытие файла. Ниже показано, как закрыть файл.
#include
int close(int fd);
Очевидно, что это базовая операция. Однако есть один важный момент, касающийся закрытия файлов, о котором следует помнить — она может завершиться сбоем. Некоторые системы (в первую очередь, следует вспомнить сетевые файловые системы вроде NFS) не пытаются поместить последнюю порцию записываемых данных в файл до тех пор, пока он не будет закрыт. Если такая операция вызовет сбой (например, по причине недоступности удаленного хоста), то close()
вернет ошибку. Если ваше приложение пишет данные, но не синхронизирует записи (см. обсуждение O_SYNC
в следующем разделе), то вы всегда должны проверять результат закрытия файла. Если close()
дает сбой, то это значит, что обновленный файл поврежден самым непредсказуемым образом! К счастью подобное случается достаточно редко.
11.2.3. Открытие файлов в файловой системе
Хотя Linux предусматривает множество типов файлов, обычные файлы используются наиболее часто. Программы, конфигурационные файлы, файлы данных — все они подпадают под это определение, и многие приложения не могут (явно) использовать файлы любых других типов. Есть два способа открытия файла, который имеет ассоциированное с ним имя.
#include
#include
int open(char *pathname, int flags, mode_t mode);
int creat(char *pathname, mode_t mode);
Функция open()
возвращает файловый дескриптор, указывающий на pathname
. Если возвращенное значение меньше нуля, значит, произошла ошибка (как всегда, errno
содержит код ошибки). Аргумент flags
описывает тип доступа, который нужен вызывающему процессу, а также управляет различными атрибутами открытия и манипулирования файлом. Режим доступа всегда должен быть указан, и он может быть одним из следующих: O_RDONLY
, O_RDWR
либо O_WRONLY
, что запрашивает доступ, соответственно, только по чтению, по чтению и записи либо только по записи. С этим режимом может быть объединены логическим "И" следующие значения для управления прочей семантикой файлов.