Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лек_1_10_Интерфейс с файловой системой.doc
Скачиваний:
1
Добавлен:
21.09.2019
Размер:
158.72 Кб
Скачать

Стандартная библиотека ввода/вывода

Традиционной для ОС UNIX библиотекой функций более высокого уровня, чем библиотека системных вызовов, является, так называемая, стандартная библиотека ввода/вывода (stdio). Основной набор функций этой библиотеки служит для выполнения файловых операций с буферизацией данных в памяти пользовательского процесса и предоставляет более удобный стиль програмирования. Библиотека ввода/вывода фактически стандартизована очень давно, и ей можно безопасно пользоваться в любой операционной среде. В частности, единообразные библиотеки ввода/вывода поддерживаются во всех современных реализациях системы программирования языка Си, выполненных не только в среде ОС UNIX (например, реализация в среде MS-DOS).

Поэтому можно сформулировать правило мобильного программирования с использованием библиотеки ввода/вывода:

Если для разрабатываемой вами прикладной программы достаточно возможностей библиотеки ввода/вывода, ограничьтесь использованием этой библиотеки.

Придерживаясь этого правила, с большой вероятностью вы не будете иметь проблем, связанных с вводом/выводом, при переносе вашей программы в любую операционную среду (не обязательно UNIX-ориентированную), в которой поддерживается стандартная библиотека ввода/вывода.

Вместо использования файлового дескриптора библиотека определяет указатель на специальную структуру данных FILE, которая условно называется указателем на файл (file pointer). Структура FILE содержит в себе:

_file дескриптор файла для обращения к системным вызовам;

_base указатель на буфер, размещенный в памяти программы;

_ptr указатель на текущее место в буфере, откуда надо выдать или куда записать очередной символ; этот указатель продвигается при каждом вызове getc(3) или putc(3);

_cnt счетчик оставшихся в буфере символов (при чтении) или свободного места (при записи);

_flag флаги состояния потока (режимы открытия файла: чтение/запись/чтение+запись; текущее состояние файла, например, одно из состояний - при чтении файла был достигнут его конец)

и др. поля (всего 9)

Рис. 1 Структуры данных потока

Каждая программа начинает работу с тремя уже открытыми дескрипторами файлов. Это стандартные структуры FILE, указатели на которые называются stdin, stdout и stderr и связаны с дескрипторами 0, 1, 2. Они определены следующим образом:

extern FILE *stdin; /*риптор 0, стандартный ввод*/

extern FILE *stdout; /*дескриптор 1, стандартный вывод*/

extern FILE *stderr; /*дескриптор 2 стандартный ввод сообщений для ошибок*/

Эти каналы открыты неявно (автоматически при загрузке командного интерпретатора) и, если не перенаправлены, связаны с вводом с клавиатуры и выводом на терминал.

Функция fileno(3) возвращает дескриптор файла. Аргументом функции является указатель типа FILE.

Библиотека предоставляет три типа буферизации:

Полная буферизация. В этом случае операция чтения или записи завершается после того, как будет заполнен буфер ввода/вывода. Ввод/вывод для дисковых файлов, как правило, полностью буферизуется. Буфер создается (в ОП, принадлежащей процессу) функцией malloc(3) при открытии файла (вот тут я не выяснила: либо при помощи функции fopen(3), либо при первом обращении к потоку для чтения или записи) и заполняется системными вызовами read(2) или write(2). Т.о. после открытия файла все операции обмена с файлом происходят не по 1 байту, а большими порциями размером с буфер - обычно по 512 байт (константа BUFSIZ). Буфер записи "выталкивается" в файл (освобождается) в таких случаях:

  • буфер заполнен (содержит BUFSIZ символов).

  • при закрытии файла (close(2), fclose(3) или exit(код возврата) ).

  • при вызове функции fflush(3).

  • в специальном режиме после помещения в буфер символа '\n' (см. ниже)

  • в некоторых версиях UNIX перед любой операцией чтения из канала stdin (например,

при вызове gets(3)), при условии, что stdout буферизован построчно (что по умолчанию так и есть).

Построчная буферизация. В этом случае фактический ввод/вывод выполняется построчно при обнаружении конца строки '\n'. Такой тип буферизации обычно используется для потоков, ассоциированных с терминалом (т.е. стандартными потоками ввода/вывода).

Отсутствие буферизации. В этом случае не производится никакой буферизации. Отсутствие буферизации характерно для стандартного потока вывода сообщений об ошибках (Почему? Спросить у студентов).

Характер буферизации может быть изменен при помощи функций setbuf (3)и setvbuf(3), прототипы которых описаны в <stdio.h>. Первая функция позволяет включить/отключить буферизацию, а вторая устанавливает один из трех вышеперечисленных типов буферизации.

Функция fflush(3) «форсирует» запись данных из буфера на диск. Системные вызовы для этих целей – fsync(2) и fdatasync(2).

Дополнительные библиотеки

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

Наиболее безопасным решением на сегодняшний день (при программировании на языке Си) является использование библиотек, специфицированных в стандарте языка Си. Наверное, стандартных библиотек Си окажется недостаточно в случае сложных приложений, но если при указании опции "ANSI" при компиляции система программирования успешно производит сборку выполняемой программы, можно быть почти уверенным, что программа не будет иметь проблем при переносе на компьютер, на котором установлен компилятор стандартного языка Си.

Поэтому можно сформулировать правило мобильного программирования с использованием дополнительных библиотек:

Если для разрабатываемой вами прикладной системы оказывается достаточным использование библиотек, специфицированных в стандарте языка Си, ограничьтесь использованием этих библиотек.

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