Большинство программ должно делать некоторый ввод (чтение данных) или вывод, или наиболее часто оба, чтобы сделать что-нибудь полезное. Библиотека GNU С обеспечивает такой большой выбор функций ввода и функций вывода, что самая трудная часть решить, которая функция является наиболее подходящей!
Эта глава представляет понятия и терминологию, имеющие отношение к вводу и выводу. Другие главы, имеющие отношение к средствам ввода-вывода GNU:
Прежде, чем Вы сможете читать или писать содержимое файла, Вы должны установить соединение или канал связи с файлом. Этот процесс называется открытием файла. Вы можете открывать файл для чтения, записи, или для того и другого.
Соединение с открытым файлом представляется или как поток или как описатель файла. Вы передаете его как аргумент функциям, которые делают фактическое чтение или операции записи. Некоторые функции ожидают потоки, а некоторые разработаны для взаимодействия с описателями файла.
Когда Вы закончили читать из или писать в файл, Вы можете завершать соединение, закрывая файл. Если только Вы закрыли поток или описатель файла, Вы не можете больше делать операции ввода-вывода на нем.
Когда Вы хотите осуществлять ввод или выводить в файл, Вы имеете выбор из двух базисных механизмов для представления соединения между вашей программой и файлом. Это описатели файла и потоки. Описатели файла представляются как объекты типа int, в то время как потоки представляются как объекты FILE* (указатели).
Описатели файла обеспечивают примитивный интерфейс низкого уровня для операций ввода и вывода. И описатели файла, и потоки могут представлять соединение с устройством (типа терминала), или с трубопрводом или с гнездом для сообщения с другим процессом, также как с нормальным файлом. Но, если Вы хотите осуществлять операции управления, которые являются специфическими для специфического вида устройства, Вы должны использовать описатель файла; не имеется никаких средств, чтобы использовать для этого потоки. Вы должны также использовать описатели файла, если ваша программа должна делать ввод или выводить в специальных режимах, типа неблокированный (или опрошенный) ввод (см. раздел 8.10 [Флаги состояния файла]).
Потоки обеспечивают интерфейс более высокого уровня, основанный на примитивных средствах описателя файла. Интерфейс потока хорошо обрабатывает все виды файлов, единственная сложность - три стиля буферизации, которую Вы можете выбирать (см. раздел 7.17 [Буферизация потока]).
Основное преимущество использования интерфейса потока - то, что набор функций для выполнения фактического ввода и вывода (в противоположность операциям управления) на потоках является намного более богатым и более мощным чем соответствующие средства для описателей файла. Интерфейс описателя файла обеспечивает только простые функции для пересылки блоков символов, а интерфейс потока обеспечивает мощный форматируемый ввод и вывода (printf и scanf) также как функции для символьно- и строко- ориентированного ввода и вывода.
Так как потоки выполнены в терминах описателей файла, Вы можете извлекать описатель файла из потока и выполнять операции низкого уровня непосредственно на описателе файла. Вы можете также первоначально открывать соединение как описатель файла, а потом делать поток, связанный с этим описателем файла.
Вообще, Вы должны ограничиться использованием потоков, если не имеется некоторой специфической операции, которая может быть выполнена только на описателе файла. Если Вы - начинающий программист и не уверены, какие функции использовать, мы предлагаем Вам концентрироваться на форматируемых функциях (см. раздел 7.11 [Форматируемый ввод] и раздел 7.9 [Форматируемый вывод]).
Если Вы думаете о переносимости ваших программ на не-GNU системы, Вы должны также осознавать, что описатели файла не так переносимы как потоки. Вы можете ожидать что любая ANSI система поддерживает потоки, но не-GNU системы не могут поддерживать описатели файла вообще или могут выполнять только подмножество функций GNU, которые функционируют на описателях файла. Большинство функций описателя файла в библиотеке GNU включено в стандарт POSIX.1.
Один из атрибутов открытого файла - позиция файла, которая следит, где в файле следующий символ должен прочитаться или написаться. В системе GNU, и всех POSIX.1 системах, позиция файла - просто целое число, представляющее число байтов от начала файла.
Позиция файла обычно устанавливается в начало файла, когда он открыт, и каждый раз когда символ читается или пишется, позиция файла увеличивается. Другими словами, доступ к файлу обычно последователен.
Обычные файлы разрешают чтение или запись в любую позицию внутри файла. Некоторые другие виды файлов могут также разрешать это. Файлы, которые разрешают это иногда упоминаются как файлы прямого доступа. Вы можете изменять позицию файла, используя функцию fseek на потоке (см. раздел 7.15 [Позиционирование файла]) или функцию lseek на описателе файла (см. раздел 8.2 [Примитивы ввода - вывода]). Если Вы пробуете изменять позицию файла в файле, который не поддерживает произвольный доступ, Вы получите ошибку ESPIPE.
Потоки и описатели, которые открыты для дописывания обрабатываются особенно для вывода: вывод в такие файлы всегда конкатенируется последовательно к концу файла, независимо от позиции файла. Но, позиция файла все еще используется, чтобы управлять, где в файле производить выполняемое чтение.
Если Вы подумаете относительно этого, вы поймете, что несколько программ могут читать данный файл в то же самое время. Каждая программа должна иметь собственный указатель файла, на который не воздействует ничего из того, что делают другие программы.
Фактически, каждое открытие файла создает отдельную позицию файла. Таким образом, если Вы открываете файл дважды даже в той же самой программе, Вы получаете два потока или описатели с независимыми позициями файла.
Напротив, если Вы открываете описатель а потом дублируете его, чтобы получить другой описатель, эти два описателя совместно используют ту же самую позицию файла: изменение позиции файла одного описателя будет воздействовать на другой.
Чтобы открывать соединение с файлом, или выполнять другие операции типа удаления файла, Вы нуждаетесь в некотором способе обращения к файлу. Почти все файлы имеют имена, которые представляются строками.
Эти строки называются именами файла. Вы определяете имя файла, чтобы указывать, который файл Вы хотите открыть или обработать.
Этот раздел описывает соглашения для имен файла и как операционная система работает с ними.
Чтобы понимать синтаксис имен файла, Вы должны понять, как файловая система организована посредством иерархии каталогов.
Каталог - это файл, который содержит информацию, связыывающую имена других файлов; эти ассоциации называются выходами каталога или узами. Иногда, люди говорят "файлы в каталоге", но фактически, каталог только содержит указатели на файлы, а не файлы непосредственно.
Имя каталога содержащего файл, называется компонентом имени файла. Вообще, имя файла это последовательность из одного или большего количества таких компонентов, отделяемых символом наклонной черты вправо ("/").
Некоторые другие документы, типа POSIX стандарта, используют термин путь для того, что мы называем имя файла, и компонент пути для того, что это руководство вызывает компонент имени файла. Мы не используем эту терминологию, потому что "путь" - это что-нибудь полностью отличное (список каталогов для поиска), и мы думаем, что "имя пути", используемое для чего-нибудь еще будет запутывать пользователей. В документации GNU мы всегда используем "имя файла" и "компонент имени файла" (или иногда только "компонент", где контекст очевиден).
Вы можете найти более детализированную информацию относительно операций с каталогами в Главе 9 [Интерфейс файловой системы].
Имя файла состоит из компонентов имени файла, отделяемых наклонной чертой вправо ("/"). В системах, которые поддерживает библиотека GNU С, многократные последовательные символы `/' эквивалентны одиночному символу `/'.
Процесс определения, к какому файлу относится имя файла называется назначение имени файла. Это реализуется, исследованием компонентов, которые составляют имя файла слева направо, и размещением каждого последовательныого компонента в каталоге, именованном предыдущим компонентом. Конечно, каждый из файлов, которые названы каталогами, должен фактически существовать, и быть каталогом вместо регулярного файла, и иметь соответствующие права, чтобы быть доступным различным процессам; иначе неправильно назначено имя файла.
Если, имя файла начинается с "/", первым компонентом в имени файла принимается корневой каталог процесса (обычно все процессы в системе имеют тот же самый корневой каталог). Такое имя файла называется абсолютным именем файла.
Иначе, первый компонент в имени файла есть текущий рабочий каталог (см. раздел 9.1 [Рабочий каталог]). Этот вид имени файла называется именем файла прямого доступа.
Компоненты имени файла "." ("точка") и ".." ("точка - точка") имеют специальные значения. Каждый каталог имеет входы для этих компонентов имени файла. Компонент имени файла "." относится к каталогу непосредственно, в то время как компонент имени файла ".." относится к каталогу предыдущего уровня (каталог, который содержит связь для рассматриваемого каталога). Как частный случай, ".." в корневом каталоге относится к корневому каталогу непосредственно, так как он не имеет никакого родителя; таким образом "/.." тоже что и "/".
Вот несколько примеров имен файла:
"/a" файл, с именем "а", в корневом каталоге.
"/a/b" файл, с именем "b", в каталоге с именем "а" в корневом каталоге.
"а" файл, с именем "а" в текущем рабочем каталоге.
"/a/./b" Это то же, что и "/a/b".
"./a" файл с именем "а", в текущем рабочем каталоге.
"../a" файл с именем "а", в директории предыдущего уровня текущего
рабочего каталога.
Имя файла, которое есть имя каталога может необязательно
заканчиваться на "/". Вы можете определять имя файла "/" чтобы
обратиться к корневому каталогу, но пустая строка - не имя файла. Если
Вы хотите обратиться к текущему рабочему каталогу, используйте имя файла
"." или "./".
В отличие от некоторых других операционных систем, система GNU не имеет ни какой встроенной поддержки типов файлов (или расширений) или версий как частей синтаксиса имени файла. Много программ и утилит использют соглашения для имен файлов, например, файлы, содержащие исходный текст C обычно имеют имена, с прибавленным ".c" но непосредственно в файловой системе не имеется ничего, что предписывает этот вид соглашения.
Функции, которые принимают как аргументы имена файлов обычно, обнаруживают эти errno - условия ошибки в отношении синтаксиса имени файла. Эти ошибки упоминаются в этом руководство как обычные синтаксические ошибки имени файла.
EACCES
Процесс не имеет права поиска для каталога - компонента имени
файла.
ENAMETOOLONG
Эта ошибка используется, когда или общая длина имени файла большае
чем PATH_МАX, или когда индивидуальный компонент имени файла имеет длину
больше чем NAME_MAX. См. раздел 27.6 [Ограничения для файлов].
В системе GNU, не имеется никакого наложенного ограничения полной длины имени файла, но некоторые файловые системы могут иметь ограничения длины компонента.
ENOENT
Об этой ошибке сообщается, когда файл, вызванный как каталог
компонент в имени файла не существует, или когда компонент есть
символическая связь, чей выходной файл не существует. См. раздел 9.4
[Символические связи].
ENOTDIR
Файл, который вызван как, каталог - компонент имени файла
существует, но это не каталог.
ELOOP
Слишком много символических связей было рассмотрено при попытке
поиска имени файла. Система имеет произвольное ограничение числа
символических связей, которые могут быть запомнены при поиске одиночного
имени файла, как примитивный способ обнаружить циклы. См. раздел 9.4
[Символические связи].
Правила для синтаксиса имен файла обсуждаемые в разделе 6.2 [Имена файла], являются правилами, обычно используемыми системой GNU и другими POSIX системами. Однако, другие операционные системы могут использовать другие соглашения.
Имеются две причины, почему для Вас важно осознавать проблемы переносимости имени файла:
Стандарт POSIX.1 разрешает, чтобы реализации поместили дополнительные ограничения на синтаксис имени файла, относительно того, какие символы разрешаются в именах файла и на длину имени файла и строк компонентов имени файла. Однако, в системе GNU, Вы не должны волноваться относительно этих ограничений; любой символ за исключением пустого символа допускается в строке имени файла, и не имеется никаких ограничений на длины строк имени файла.