- •1.Интерфейс системных вызовов
- •2.Стандартная библиотека ввода/вывода
- •1.2. Системные вызовы и их особенности при работе с файлами.
- •1.2.1. Открытие файла. Системный вызов open().
- •1.2.2. Закрытие файла. Системный вызов close().
- •1.2.3. Чтение и запись из/в файл(а). Системные вызовы read() и write().
- •1.2.4. Создание файла. Системный вызов creat().
- •1.2.5. Создание жесткой ссылки. Системный вызов link().
- •1.2.6. Удаление жесткой ссылки. Системный вызов unlink().
- •1.2.7. Установка указателя в файле. Системный вызов lseek().
- •1.2.8. Дублирование существующего файлового дескриптора. Системный вызов dup().
- •1.2.9. Создание однонаправленного канала. Системный вызов pipe().
- •1.3. Стандартная библиотека ввода/вывода (stdio.H).
- •1.3.1. Особенности работы с stdio.H.
- •1.3.2. Потоки ввода/вывода.
- •1.3.3. Обзор функций библиотеки.
- •1.3.3.1. Функция fopen(). Открытие потока.
- •1.3.3.2. Функция fclose(). Закрытие потока.
- •1.3.3.9. Функции scanf() и fscanf(). Ввод данных с преобразованием формата.
- •2.3. Пример 3. Системный вызов write()
- •2.4. Пример 4. Системный вызов unlink()
- •2.5. Пример 5. Системный вызов lseek()
- •2.6. Пример 6. Stdio.H
1.3. Стандартная библиотека ввода/вывода (stdio.H).
Традиционной для ОС UNIX библиотекой функций более высокого уровня, чем библиотека системных вызовов, является, так называемая, стандартная библиотека ввода/вывода (stdio). Основной набор функций этой библиотеки служит для выполнения файловых операций с буферизацией данных в памяти пользовательского процесса. Библиотека ввода/вывода фактически стандартизована очень давно, и ей можно безопасно пользоваться в любой операционной среде. В частности, единообразные библиотеки ввода/вывода поддерживаются во всех современных реализациях системы программирования языка Си, выполненных не в среде ОС UNIX (включая реализации в среде MS-DOS).
Для решения этих проблем была построена специальная библиотека функций, названная stdio - "стандартная библиотека ввода/вывода" (standard input/output library). Она является частью библиотеки /lib/libc.a и представляет собой надстройку над системными вызовами (т.к. в конце концов все ее функции время от времени обращаются к системе, но гораздо реже, чем если использовать системные вызовы непосредственно). Директива #include <stdio.h> включает в нашу программу файл с объявлением форматов данных и констант, используемых этой библиотекой.
1.3.1. Особенности работы с stdio.H.
Библиотеку stdio можно назвать библиотекой буферизованного обмена, а также библиотекой работы с текстовыми файлами (т.е. имеющими разделение на строки), поскольку для оптимизации обменов с диском (для уменьшения числа обращений к нему и тем самым сокращения числа системных вызовов) эта библиотека вводит буферизацию, а также предоставляет несколько функций для работы со строчно-организованными файлами.
Связь с файлом в этой модели обмена осуществляется уже не при помощи целого числа - дескриптора файла (file descriptor), а при помощи адреса "связной" структуры FILE. Указатель на такую структуру условно называют указателем на файл (file pointer). Структура FILE содержит в себе:
• дескриптор fd файла для обращения к системным вызовам;
• указатель на буфер, размещенный в памяти программы;
• указатель на текущее место в буфере, откуда надо выдать или куда записать очередной символ; этот указатель продвигается при каждом вызове getc или putc;
• счетчик оставшихся в буфере символов (при чтении) или свободного места (при записи);
• режимы открытия файла (чтение/запись/чтение+запись) и текущее состояние файла. Одно из состояний - при чтении файла был достигнут его конец;
• способ буферизации;
Предусмотрено несколько стандартных структур FILE, указатели на которые называются stdin, stdout и stderr и связаны с дескрипторами 0, 1, 2 соответственно (стандартный ввод, стандартный вывод, стандартный вывод ошибок). Напомним, что эти каналы открыты неявно (автоматически) и, если не перенаправлены, связаны с вводом с клавиатуры и выводом на терминал.
Буфер в оперативной памяти нашей программы создается (функцией malloc) при открытии файла при помощи функции fopen(). После открытия файла все операции обмена с файлом происходят не по 1 байту, а большими порциями размером с буфер - обычно по 512 байт (константа BUFSIZ).
При чтении символа:
int c; FILE *fp = ... ;
c = getc(fp);
в буфер считывается read-ом из файла порция информации, и getc выдает ее первый байт. При последующих вызовах getc выдаются следующие байты из буфера, а обращений к диску уже не происходит! Лишь когда буфер будет исчерпан - произойдет очередное чтение с диска. Таким образом, информация читается из файла с опережением, заранее наполняя буфер; а по требованию выдается уже из буфера. Если мы читаем 1024 байта из файла при помощи getc(), то мы 1024 раза вызываем эту функцию, но всего 2 раза системный вызов read - для чтения двух порций информации из файла, каждая - по 512 байт.
При записи:
char c; FILE *fp = ... ;
putc(c, fp);
выводимые символы накапливаются в буфере. Только когда в нем окажется большая порция информации, она за одно обращение write записывается на диск. Буфер записи "выталкивается" в файл в таких случаях:
- буфер заполнен (содержит BUFSIZ символов).
- при закрытии файла (fclose или exit).
- при вызове функции fflush.
- в специальном режиме - после помещения в буфер символа '\n' .
- в некоторых версиях - перед любой операцией чтения из канала stdin (например, при вызове gets), при условии, что stdout буферизован построчно (режим _IOLBF), что по умолчанию так и есть.