Файл: Linux. Системное программирование. Вступление.pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 28.04.2024

Просмотров: 56

Скачиваний: 0

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

1   ...   6   7   8   9   10   11   12   13   14

104
Режимы. Аргумент mode описывает, как открывать конкретный файл. Данный аргумент может быть представлен одной из следующих строк.

r
— файл открывается для чтения. Поток данных устанавливается в начале файла.

r+
— файл открывается как для чтения, так и для записи. Поток данных уста­
навливается в начале файла.

w
— файл открывается для записи. Если файл существует, то он усекается до нулевой длины. Если файл не существует, он создается. Поток данных устанав­
ливается в начале файла.

w+
— файл открывается для чтения и для записи. Если файл существует, то он усекается до нулевой длины. Если файл не существует, он создается. Поток данных устанавливается в начале файла.

a
— файл открывается для дополнения в режиме дозаписи. Если файл не суще­
ствует, то он создается. Поток данных устанавливается в конце файла. Все вводимые данные дозаписываются в файл.

a+
— файл открывается для дополнения и считывания в режиме дозаписи. Если файл не существует, то он создается. Поток данных устанавливается в конце файла. Все вводимые данные дозаписываются в файл.
ПРИМЕЧАНИЕ
В указанном режиме также может содержаться символ b, хотя в Linux это значение всегда игнорирует- ся. Некоторые операционные системы по-разному обрабатывают текст и двоичные файлы. Сим- вол b означает, что файл должен быть открыт именно в двоичном режиме. Linux, как и все операцион- ные системы, соответствующие стандарту POSIX, воспринимает текст и двоичные файлы одинаково.
В случае успеха функция fopen()
возвращает допустимый указатель
FILE
. При ошибке она возвращает
NULL
и устанавливает errno соответствующее значение.
Например, следующий код открывает для чтения файл
/etc/manifest и ассоци­
ирует его с потоком данных stream
:
FILE *stream;
stream = fopen ("/etc/manifest", "r");
if (!stream)
/* ошибка */
Открытие потока данных
с помощью файлового дескриптора
Функция fdopen()
преобразует уже открытый файловый дескриптор (
fd
) в поток данных:
#include
FILE * fdopen (int fd, const char *mode);
Глава 3. Буферизованный ввод-вывод

105
Могут использоваться те же режимы, что и с функцией fopen()
, при этом они должны быть совместимы с режимами, которые изначально применялись для от­
крытия файлового дескриптора. Режимы w и w+
можно указывать, но они не будут приводить к усечению файла. Поток данных устанавливается в файловую позицию, которая соответствует данному файловому дескриптору.
После преобразования файлового дескриптора в поток данных ввод­вывод больше не выполняется напрямую с этим файловым дескриптором. Тем не менее это не возбраняется. Обратите внимание: файловый дескриптор не дублируется, а просто ассоциируется с новым потоком данных. При закрытии потока данных закроется и файловый дескриптор.
В случае успеха fdopen()
возвращает допустимый указатель файла, при ошибке она возвращает
NULL
и присваивает errno соответствующее значение.
Например, следующий код открывает файл
/home/kidd/map.txt с помощью сис­
темного вызова open()
, а потом создает ассоциированный поток данных, опираясь на базовый файловый дескриптор:
FILE *stream;
int fd;
fd = open ("/home/kidd/map.txt", O_RDONLY);
if (fd == -1)
/* ошибка */
stream = fdopen (fd, "r");
if(!stream)
/* ошибка */
Закрытие потоков данных
Функция fclose()
закрывает конкретный поток данных:
#include
int fclose(FILE*stream);
Сначала сбрасываются на диск все буферизованные, но еще не записанные данные. В случае успеха fclose()
возвращает
0
. При ошибке она возвращает
EOF
(конец файла) и устанавливает errno в соответствующее значение.
Закрытие всех потоков данных. Функция fcloseall()
закрывает все потоки данных, ассоциированные с конкретным процессом, в частности используемые для стандартного ввода, стандартного вывода и стандартных ошибок:
#define _GNU_SOURCE
#include
int fcloseall(void);
Перед закрытием все потоки данных сбрасываются на диск. Функция является специфичной для Linux и всегда возвращает
0
Закрытие потоков данных


106
Считывание из потока данных
Теперь, когда мы умеем открывать и закрывать потоки данных, поговорим о том, как сделать что­то полезное — как считать поток данных, а затем как записать в него информацию.
Стандартная библиотека C реализует множество функций для считывания из открытого потока данных. Среди них есть как общеизвестные, так и мало­
распространенные. В этом разделе мы рассмотрим три наиболее популярных варианта считывания: считывание одного символа в момент времени, считыва­
ние целой строки в момент времени, считывание двоичных данных. Чтобы из потока данных можно было считать информацию, он должен быть открыт как поток данных ввода в подходящем режиме, то есть в любом допустимом режи­
ме, кроме w
и a
Считывание одного символа в момент времени
Зачастую идеальный принцип ввода­вывода сводится к считыванию одного сим­
вола в момент времени. Функция fgetc()
используется для считывания отдельно­
го символа из потока данных:
#include
int fgetc(FILE*stream);
Эта функция считывает следующий символ из stream и возвращает его как unsigned char
, приведенный к int
. Такое приведение осуществляется, чтобы получить достаточно широкий диапазон для уведомлений EOF или описания ошибок: в та­
ких случаях возвращается
EOF
. Возвращаемое значение fgetc()
должно быть сохра­
нено в int
. Сохранение в char
— распространенный и опасный промах, ведь в таком случае вы не можете обнаруживать ошибки.
В следующем коде мы считываем отдельно взятый символ из stream
, проверяем наличие ошибок и выводим результат как char
:
int c;
c = fgetc (stream);
if (c == EOF)
/* ошибка */
else printf ("c=%c\n", (char) c);
Поток данных, указанный в stream
, должен быть открыт для чтения.
Возврат символа в поток данных. В рамках стандартного ввода­вывода предо­
ставляется функция для перемещения символа обратно в поток данных. С ее по­
мощью вы можете «заглянуть» в поток данных и возвратить символ обратно, если окажется, что он вам не подходит:
Глава 3. Буферизованный ввод-вывод