72534

Программный интерфейс к файловой системе UNIX

Лекция

Информатика, кибернетика и программирование

Инициализация файла: трансляция имени файла в файловый дескриптор номер в таблице дескрипторов внутри процесса; Создание записи в системной файловой таблице которая содержит права доступа к файлу текущую позицию указателя в нем и другую информацию; эта таблица общая для всех процессов.

Русский

2014-11-24

70.42 KB

1 чел.

Программный интерфейс к файловой системе UNIX

  1.  Обработка файлов из программы на Си.

  1.  Порядок обработки.

    При обработке файлов, важнейшими являются режимы ОТКРЫТИЯ и ЗАКРЫТИЯ файла. Эти режимы взаимоисключающие. В ОС UNIX все действия по определению режима работы с файлом устанавливаются при его открытии. Сюда входит:

  1.  Инициализация файла: трансляция имени файла в файловый дескриптор (номер) в таблице дескрипторов внутри процесса;
  2.  Создание записи в системной файловой таблице, которая содержит права доступа к файлу, текущую позицию указателя в нем и другую информацию; эта таблица общая для всех процессов.

Все эти операции проводятся автоматически при вызове open(). Ядро само создает цепочку от файлового дескриптора до inode(vnode) файла, и далее до блоков данных.

Несколько процессов могут одновременно работать с одним и тем же файлом, для этого в системной файловой таблице создаются несколько записей, ссылающихся на один и тот же файл; количество таких процессов указывается в поле f_count.

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

  1.  Запись файл всего, что не было записано и было кэшировано в оперативной памяти
  2.  Удаление дескриптора из системной и внутрипроцессной файловой таблицы

 

    В Unix-системах нет операции удаления файла в том смысле, какой существует в Windows. Есть только удаление ссылки на узел - unlink - и ссылки на пустой каталог - rmdir. Сам же файл автоматически удаляется тогда, когда делается недоступным для системы. Это означает, что не должно остаться, во-первых, ни одной ссылки на него, а во-вторых, ни одной работающей с ним активной программы. К слову, именно поэтому в Unix/Linux можно обойтись без перезагрузки практически при любом изменении системы (за исключением замены ядра ОС). Чтобы обновить системную библиотеку, вы стираете её прежнюю версию (т.е. освобождаете соответствующую ссылку) и записываете под тем же именем новую. Ядро откладывает момент удаления библиотеки до тех пор, пока не закончит работу последняя из программ, её использующая (что может произойти спустя долгое время).

    В среде программирования UNIX существуют два основных интерфейса для файлового ввода/вывода:

1.Интерфейс системных вызовов

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

1.2. Системные вызовы и их особенности при работе с файлами.

    Для работы с каким-либо файлом наша программа должна открыть этот файл -  установить  связь  между  именем  файла и некоторой переменной в программе.  При открытии файла в ядре операционной системы выделяется  "связующая"  структура  file  "открытый файл", содержащая:

  f_offset:

    указатель позиции чтения/записи, который в дальнейшем мы  будем  обозначать  как RWptr.  Это  long-число,  равное  расстоянию в байтах от начала файла до позиции чтения/записи;

  f_flag:

    режимы открытия файла: чтение, запись, чтение и запись, некоторые дополнительные флаги;

  f_inode:

    расположение файла на диске.

    При  открытии  файла  в  этой  таблице  ищется свободная ячейка, в нее заносится ссылка на  структуру  "открытый  файл"  в  ядре, и ИНДЕКС  этой  ячейки выдается в вашу программу в виде целого числа -  так называемого

"дескриптора файла".

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

    Дескрипторы являются локальными для каждой программы.  Т.е. если две  программы открыли  один  и тот же файл - дескрипторы этого файла в каждой из них не обязательно совпадут (хотя и могут).  Обратно: одинаковые дескрипторы (номера) в разных  программах  не  обязательно  обозначают один и тот же файл.

 1.2.1. Открытие файла. Системный вызов open().

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

Прототип системного вызова

#include <fcntl.h>

int open(char *path, int flags);

int open(char *path, int flags, int mode);

Описание системного вызова

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

Параметр path является указателем на строку, содержащую полное или относительное имя файла.

Параметр flags может принимать одно из следующих трех значений:

O_RDONLY – если над файлом в дальнейшем будут совершаться только операции чтения;

O_WRONLY – если над файлом в дальнейшем будут осуществляться только операции записи;

O_RDWR – если над файлом будут осуществляться и операции чтения, и операции записи.

Каждое из этих значений может быть скомбинировано посредством операции "побитовое или ( | )" с одним или несколькими флагами:

O_CREAT – если файла с указанным именем не существует, он должен быть создан;

O_EXCL – применяется совместно с флагом O_CREAT. При совместном их использовании и существовании файла с указанным именем, открытие файла не производится и констатируется ошибочная ситуация;

O_NDELAY – запрещает перевод процесса в состояние ожидание при выполнении операции открытия и любых последующих операциях над этим файлом;

O_APPEND – при открытии файла и перед выполнением каждой операции записи (если она, конечно, разрешена) указатель текущей позиции в файле устанавливается на конец файла;

O_TRUNC – если файл существует, уменьшить его размер до 0, с сохранением существующих атрибутов файла, кроме, быть может, времен последнего доступа к файлу и его последней модификации.

O_SYNC – любая операция записи в файл будет блокироваться (т. е. процесс будет переведен в состояние ожидание) до тех пор, пока записанная информация не будет физически помещена на соответствующий нижележащий уровень hardware;

O_NOCTTY – если имя файла относится к терминальному устройству, оно не становится управляющим терминалом процесса, даже если до этого процесс не имел управляющего терминала.

Параметр mode устанавливает атрибуты прав доступа различных категорий пользователей к новому файлу при его создании. Он обязателен, если среди заданных флагов присутствует флаг O_CREAT, и может быть опущен в противном случае. Этот параметр задается как сумма следующих восьмеричных значений:

0400 – разрешено чтение для пользователя, создавшего файл;

и т.д.

При создании файла реально устанавливаемые права доступа получаются из стандартной комбинации параметра mode и маски создания файлов текущего процесса umask, а именно – они равны mode & ~umask.

Возвращаемое значение

Системный вызов возвращает значение файлового дескриптора для открытого файла при нормальном завершении и значение -1 при возникновении ошибки.

1.2.2. Закрытие файла. Системный вызов close().

Прототип системного вызова:

#include <unistd.h>

int close(int fd);

Описание системного вызова

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

Параметр fd является дескриптором соответствующего объекта.

Возвращаемое значение

    Системный вызов возвращает значение 0 при нормальном завершении и значение   -1 при возникновении ошибки.

-> Пример 1

1.2.3. Чтение и запись из/в файл(а). Системные вызовы read() и write().

    Системные вызовы read и write предназначены для осуществления потоковых операций ввода (чтения) и вывода (записи) информации над каналами связи, описываемыми файловыми дескрипторами. При работе с файлами информация записывается в файл или читается из него, начиная с места, определяемого указателем текущей позиции в файле. Значение указателя увеличивается на количество реально прочитанных или записанных байт.

Прототипы системных вызовов

#include <sys/types.h>

#include <unistd.h>

size_t read(int fd, void *addr, size_t nbytes);

size_t write(int fd, void *addr, size_t nbytes);

Описание системных вызовов

Системные вызовы read и write предназначены для осуществления потоковых операций ввода (чтения) и вывода (записи) информации над каналами связи, описываемыми файловыми дескрипторами, т.е. для файлов, pipe, FIFO и socket.

Параметр fd является файловым дескриптором созданного ранее потокового канала связи, через который будет отсылаться или получаться информация, т. е. значением, которое вернул один из системных вызовов open(), pipe() или socket().

Параметр addr представляет собой адрес области памяти, начиная с которого будет браться информация для передачи или размещаться принятая информация.

Параметр nbytes для системного вызова write определяет количество байт, которое должно быть передано, начиная с адреса памяти addr. Параметр nbytes для системного вызова read определяет количество байт, которое мы хотим получить из канала связи и разместить в памяти, начиная с адреса addr.

Тип данных size_t обычно является синонимом типа long.

Возвращаемые значения

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

Особенности поведения при работе с файлами

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

-> Примеры 2 и 3

1.2.4. Создание файла. Системный вызов creat().

Прототип системного вызова:

#include <fcntl.h>

int creat(const char *path, int  mode);

Описание системного вызова

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

    Как и для вызова ореn, аргумент path определяет имя файла в файловой системе, a mode — устанавливаемые права доступа к файлу.

    Системный вызов creat эквивалентен системному вызову open() с параметром flags, установленным в значение O_CREAT | O_WRONLY | O_TRUNC.

Возвращаемые значения

    Системный вызов возвращает значение файлового дескриптора для открытого файла при нормальном завершении и значение -1 при возникновении ошибки.

1.2.5. Создание жесткой ссылки. Системный вызов link().

Прототип системного вызова:

#include <unistd.h>

int link(char *pathname, char *linkpathname);

Описание системного вызова

    Системный вызов link служит для создания жесткой связи к файлу с именем, на которое указывает параметр pathname. Указатель на имя создаваемой связи задается параметром linkpathname (полное или относительное имя связи). Во всех существующих реализациях операционной системы UNIX запрещено создавать жесткие связи к директориям. В операционной системе Linux (по непонятной причине) дополнительно запрещено создавать жесткие связи к специальным файлам устройств. Надо отметить, что системный вызов link является одним из немногих системных вызовов, совершающих операции над файлами, которые не требуют предварительного открытия файла.

Возвращаемые значения

    Системный вызов возвращает значение 0 при нормальном завершении и значение   -1 при возникновении ошибки (если файл с именем создаваемой связи уже существует; а также если мы попытаемся создать связь на другом физическом внешнем устройстве).  

1.2.6. Удаление жесткой ссылки. Системный вызов unlink().

Прототип системного вызова:

#include <unistd.h>

int unlink(char *pathname);

 Описание системного вызова

  Системный вызов unlink служит для удаления имени, на которое указывает параметр pathname, из файловой системы.

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

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

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

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

- если имя относится к файлу типа "связь", то он удаляется, и мягкая связь оказывается разорванной.

Возвращаемые значения

    Системный вызов возвращает значение 0 при нормальном завершении и значение   -1 при возникновении ошибки.

Пример 4

1.2.7. Установка указателя в файле. Системный вызов lseek().

Прототип системного вызова:

#include <sys/types.h>

#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);

Описание системного вызова

    Системный вызов lseek предназначен для изменения положения указателя текущей позиции в открытом регулярном файле.

    Параметр fd является дескриптором соответствующего файла, т. е. значением, которое вернул системный вызов open().

    Параметр offset совместно с параметром whence определяют новое положение указателя текущей позиции следующим образом:

- если значение параметра whence равно SEEK_SET, то новое значение указателя будет составлять offset байт от начала файла.

- если значение параметра whence равно SEEK_CUR, то новое значение указателя будет составлять старое значение указателя + offset байт.

    Если значение параметра whence равно SEEK_END, то новое значение указателя будет составлять длина файла + offset байт.

    Естественно, что новое значение указателя не должно стать отрицательным.

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

Тип данных off_t обычно является синонимом типа long.

Возвращаемые значения

    Системный вызов возвращает новое положение указателя текущей позиции в байтах от начала файла при нормальном завершении и значение -1 при возникновении ошибки.

Пример 5

1.2.8. Дублирование существующего файлового дескриптора. Системный вызов dup().

    Функция dup() используется для дублирования существующего файлового дескриптора:

Прототип системного вызова:

int dup(int fildes);

Описание системного вызова

    Файловый дескриптор fildes должен быть предварительно получен с помощью функций ореп(), creat(), dup(), или pipe(). В случае успешного завершения функции dup() возвращается новый файловый дескриптор, свойства которого идентичны свойствам дескриптора fildes. Оба указывают на один и тот же файл, одно и то же смещение, начиная с которого будет производиться следующая операция чтения или записи (файловый указатель), и определяют один и тот же режим работы с файлом. Правило размещения нового файлового дескриптора аналогично используемому в функции ореn().

1.2.9. Создание однонаправленного канала. Системный вызов pipe().

Прототип системного вызова:

#include <unistd.h>

int pipe(int fildes[2]);

Описание системного вызова

    Функция pipe() служит для создания однонаправленного (симплексного) канала (также называемого анонимным каналом) обмена данными между двумя родственными процессами. Дело в том, что только родственные процессы (например, родительский и дочерний) имеют возможность получить доступ к одному и тому же каналу.

    Функция возвращает два файловых дескриптора в массиве fildes [], причем fildes [0] служит для чтения данных из канала, a fildes [1] — для записи данных в канал.

Каналы являются одним из способов организации межпроцессного взаимодействия. В качестве примера использования pipe() можно привести возможность командного интерпретатора — создание программных каналов.

    Отметим, что буферизация данных в канале стандартно осуществляется путем выделения дискового пространства в структуре файловой системы. Таким образом, чтение и запись в канал связаны с дисковым вводом/выводом, что, безусловно, сказывается на производительности этого механизма. Современные операционные системы наряду с более совершенными средствами межпроцессного взаимодействия предлагают и более эффективные механизмы каналов. Так, например, SCO UNIX (OpenServer 5.0) обеспечивает работу каналов через специальную файловую систему — HPPS (High Performance Pipe System). С помощью HPPS данные буферизируются в оперативной памяти, что существенно ускоряет операции записи и чтения.

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), что по умолчанию так и есть.

1.3.2. Потоки ввода/вывода.

    Стандартная библиотека содержит многочисленные функции, использующие собственный механизм буферизации при работе с файлами. Их часто называют функциями потокового ввода/вывода. Такую буферизацию не следует путать с буферизацией, выполняемой операционной системой. Имена всех этих функций начинаются на f - fopen , fclose , fprintf и т. д.

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

    Существуют потоки, соответствующие стандартным устройствам ввода, вывода, вывода сообщений об ошибках, стандартному устройству последовательного ввода/вывода и стандартному устройство печати:

Поток

Описание

stdin

Стандартное устройство ввода;

stdout

Стандартное устройство вывода;

stderr

Стандартное устройство для вывода сообщений об ошибках;

stdaux

Стандартное последовательное устройство ввода/вывода;

stdprn

Стандартное печатающее устройство.

    Для использования этих потоков не требуются выполнять процедуру открытия и закрытия.

    Для работы со стандартными устройствами ввода/вывода в библиотеках трансляторов языка программирования С имеется соответствующий набор функций, которые должны быть вам хорошо известны - printf, scanf , putchar и т. д.

1.3.3. Обзор функций библиотеки.

Рассмотрим ряд наиболее употребляемых функций стандартной библиотеки ввода/вывода.

Таблица. Наиболее употребительные функции стандартной библиотеки ввода/вывода.

Функция

Назначение

fopen()

Открывает файл с указанным именем и возвращает файловый указатель, ассоциированный с данным файлом.

fclose()

Закрывает поток, освобождая буферы.

fflush()

Очищает буфер потока, открытого на запись.

getc()

Считывает символ из потока.

putc()

Записывает символ в поток.

gets()

Считывает строку из потока.

puts()

Записывает строку в поток.

fread()

Считывает указанное число байтов из потока (бинарный ввод).

fwrite()

Записывает указанное число байтов в поток (бинарный вывод).

fseek()

Позиционирует указатель в потоке.

printf()

Производит форматированный вывод.

scanf()

Производит форматированный ввод.

fileno()

Возвращает файловый дескриптор данного потока.

1.3.3.1. Функция fopen(). Открытие потока.

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

    Функция fopen открывает файл с именем path и связывает его с потоком.

    Параметр mode указывает на строку, начинающуюся с одной из следующих последовательностей (за ними могут следовать дополнительные символы):

r  Открыть текстовый файл для чтения. Чтение начинается с начала файла.

r+ Открыть для чтения и записи. Чтение или запись начинаются с начала файла.

w "Урезать" файл до нулевой длины или создать текстовый файл и открыть его для записи. Запись начинается с начала файла.

w+ Открыть для чтения и записи. Файл создается, если до этого его не существовало, в противном случае он "урезается". Чтение или запись начинаются с начала файла.

A Открыть для дописывания (записи в конец файла). Файл создается, если до этого его не существовало. Запись осуществляется в конец файла.

a+ Открыть для чтения и дописывания (записи в конец файла). Файл создается, если до этого его не существовало. Чтение или запись производятся с конца файла.

    При успешном завершении fopen  возвращают указатель FILE. Иначе возвращается NULL, а в глобальную переменную errno записывается код ошибки.

1.3.3.2. Функция fclose(). Закрытие потока.     

    Функция fclose отделяет указанный поток stream от связанного с ним файла или набора функций. Если поток использовался для вывода данных, то все данные, содержащиеся в буфере, сначала записываются с помощью fflush(). 

    При успешном завершении возвращается нулевое значение.

1.3.3.3. Функция fflush(). Сброс буферов потока.

    Функция fflush принудительно записывает все буферизированные данные в устройство вывода данных или корректирует поток stream посредством определенных для него функций записи. При этом поток остается открытым.

    Если аргумент stream указывает на NULL, то fflush "сбрасывает" данные всех потоков, открытых выводящим данным.  При обычном завершении работы возвращается нулевое значение.

1.3.3.4. Функции getc() и gets(). Считывание символа и строки из потока.

getc() считывает очередной символ из потока stream  

getchar() эквивалентна getc(stdin).

gets() считывает строку из stdin и записывает ее в буфер, на который указывает s, пока не встретится символ новой строки или EOF, которые заменяются значением '\0'. Проверка на переполнение буфера не производится.

gets() и fgets() возвращают s при удачном завершении операции и NULL при ошибке или если достигнут конец файла, а символы остались несчитанными.

1.3.3.5. Функции putc() и puts(). Запись символа и строки в поток.

 putc() выводит символ c, приведенный к виду unsigned char, в поток stream. putchar(c); полностью эквивалентна putc(c,stdout).

puts() записывает строку s и завершающий перевод строки в stdout.

1.3.3.6. Функции fread() и fwrite(). Ввод/вывод для бинарного файла.

Функция fread считывает элементы данных nmemb (с размером каждого size байтов) с потока, на который указывает stream, и сохраняет их в позиции, на которую указывает ptr.

Функция fwrite записывает элементы данных nmemb (с размером каждого size байтов) в поток, на который указывает stream, при получении элементов с той позиции, на которую указывает ptr.  

fread и fwrite возвращают количество элементов, успешно считанных или записанных (то есть не количество символов)

1.3.3.7. Функция fseek(). Смена положения операции в потоке.

    Функция fseek устанавливает позицию следующей операции ввода/вывода в потоке, на который указывает аргумент stream. Новая позиция получается прибавлением смещения offset байтов к начальной позиции, определяемой параметром whence. Если whence определяется как SEEK_SET, SEEK_CUR или SEEK_END, то смещение будет относиться к началу файла, текущей позиции указателя или концу файла соответственно.

1.3.3.8. Функции printf() и fprintf(). Вывод данных с преобразованием формата.

    Функции семейства printf выводят данные в соответствии с параметром format.

fprintf направляет данные в заданный поток вывода stream

    При успешном завершении работы эти функции возвращают количество напечатанных символов.

%d

целое десятичное число типа int (d - от decimal)

%lf

вещ. число типа double (lf - от long float)

%c

один символ типа char

%s

ввод строки. Из входного потока выделяется слово, ограниченое пробелами или символами перевода строки '\n'. Слово помещается в массив символов. Конец слова отмечается нулевым байтом.

1.3.3.9. Функции scanf() и fscanf(). Ввод данных с преобразованием формата.

    Функции  считывают вводимую информацию в соответствии с форматом format . Этот формат может включать в себя определители преобразования; результаты каждого преобразования, если они производились, будут сохраняться c помощью параметров указателя. Функция scanf считывает информацию, прибывающую из стандартного потока ввода stdinfscanf считывает информацию из потока, на который указывает stream

1.3.3.10. Функция feof(). Проверка конца файла.

feof проверяет, был ли достигнут конец файла, на который указывает fp.

feof возвращает 0, если конец файла еще не был достигнут, и ненулевое значение в противном случае.

Стандарт ANSI требует наличия функции feof.

Никаких процедур ОС не требуется.

3.3.4.11. Функция ferror(). Проверка на возникновение ошибки ввода/вывода.

Функция ferror проверяет ошибки чтения и  записи  заданного потока. При возникновении ошибки индикатор ошибки stream остается установленным  до тех пор, пока поток не закроется или "разрушится" (rewound)  или же пока не будет вызвана функция clearerr.

           

В случае обнаружения ошибки в потоке  функция ferror  возвращает ненулевое значение. Возвращаемое значение 0 свидетельствует об отсутствии ошибки.

Пример 6

  1.  Примеры программ

2.1. Пример 1. Системные вызовы open() и close()

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

fd = open (argv[1], O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);

Или так:

fd = open (argv[1], O_WRONLY | O_CREAT | O_EXCL, 0600);

2.2. Пример 2. Системный вызов read()

В этом примере используется укороченная версия open(), так как файл открывается только для чтения. В качестве буфера (второй аргумент read()) передается адрес переменной типа char. По этому адресу будут считываться данные из файла (по одному байту за раз) и передаваться на стандартный вывод. Цикл чтения файла заканчивается, когда read() возвращает нуль (нечего больше читать) или -1 (ошибка). Системный вызов close() закрывает файл.

Как можно заметить, в данном примере системный вызов read() вызывается ровно столько раз, сколько байт содержится в файле. Иногда это действительно нужно; но не здесь. Чтение-запись посимвольным методом (как в примере) значительно замедляет процесс ввода-вывода за счет многократных обращений к системным вызовам. По этой же причине возрастает вероятность возникновения ошибки. Если нет действительной необходимости, файлы нужно читать блоками. Ниже приведен исходный код программы, которая делает то же самое, что и предыдущий пример, но с использованием блочного чтения файла. Размер блока установлен в 64 байта.

2.3. Пример 3. Системный вызов write()

В этом примере нам уже не надо изощряться в попытках вставить нуль-терминатор в строку для записи, поскольку системный вызов write() не запишет большее количество байт, чем мы ему указали. В данном случае для демонстрации write() мы просто записывали данные в файл с дескриптором 1, то есть в стандартный вывод.

2.4. Пример 4. Системный вызов unlink()

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

2.5. Пример 5. Системный вызов lseek()

    В нашем примере: при создании файла его размер 0, и ему выделено 0 блоков. При первой записи файлу будет выделен один блок (логический блок номер 0 для файла) и в его начало запишется "begin". Длина файла станет равна 5 (остаток блока - 1019 байт - не используется и файлу логически не принадлежит!). Затем lseek поставит указатель записи далеко за конец файла и write запишет в 1000-ый блок слово "end". 1000-ый блок будет выделен на диске. В этот момент у файла "возникнут" и все промежуточные блоки 1..999. Однако они будут только "числиться за файлом", но на диске отведены не будут (в таблице блоков файла это обозначается адресом 0)! При чтении из них будут читаться байты '\0'. Это так называемая "дырка" в файле. Файл имеет размер 1024003 байта, но на диске занимает всего 2 блока (на самом деле чуть больше, т.к. часть таблицы блоков файла тоже находится в специальных блоках файла). Блок из "дырки" станет реальным, если в него что-нибудь записать.

2.6. Пример 6. stdio.h

    В качестве примера приведем текст программы BUFCOPY, копирующей содержимое текстового файла.

    Программа копирует этот файл три раза. В первый раз она использует буфер стандартного размера, затем увеличивает размер буфера в десять раз, и наконец, копирует файл без использования механизма буферизации. Каждый раз программа измеряет продолжительность копирования файла с помощью функции clock, входящей в состав стандартной библиотеки Borland C++.


 

А также другие работы, которые могут Вас заинтересовать

28572. Примеры хеш-функций 14.18 KB
  Расширение исходного сообщения Собственно хеширование . Расширение исходного битового сообщения M длины L происходит следующим образом. Алгоритм хеширования работает циклами за один цикл обрабатывается блок исходного сообщения длины 512 бит. Цикл состоит из четырех раундов каждый из которых вычисляет новые значения переменных A B C D на основании их предыдущего значения и значения 64битного отрезка хешируемого 512битного блока исходного сообщения.
28573. Примеры хеш-функций Классификация хеш-функций 13.05 KB
  На бесключевые хешфункции накладываются определенные условия. Предполагается что на вход подано сообщение состоящее из байт хеш которого нам предстоит вычислить. Эту операцию называют проверка хеша hashcheck.
28574. Примеры хеш-функций: применение хеш-функций в системах ЭЦП; хеш-функции с ключом 12.72 KB
  Чтобы избежать этого вместе с цифровой подписью используется хешфункция то есть вычисление подписи осуществляется не относительно самого документа а относительно его хеша. В этом случае в результате верификации можно получить только хеш исходного текста следовательно если используемая хешфункция криптографически стойкая то получить исходный текст будет вычислительно сложно а значит атака такого типа становится невозможной. Также существуют другие преимущества использования хешфункций вместе с ЭЦП: Вычислительная сложность.
28575. Примеры хеш-функций sha 12.54 KB
  Для входного сообщения длина которого меньше 264 бит алгоритм SHA1 выдаёт 160битовый результат. Предназначен SHA1 для использования вместе с алгоритмом цифровой подписи DSA. Цифровая подпись формируется на основе дайджеста SHA1 от сообщения что повышает эффективность процесса подписания.
28578. Сертификаты открытых ключей. Аннулирование сертификатов 20.88 KB
  Сертификаты открытых ключей. Механизмы контроля использования ключей. Подтверждение подлинности ключей Сертификат открытого ключа сертификат ЭЦП сертификат ключа подписи сертификат ключа проверки электронной подписи согласно ст. Предположим что Алиса желая получать зашифрованные сообщения генерирует пару ключей один из которых открытый она публикует какимлибо образом.
28579. Требования к качеству ключевой информации и источники ключей 16.09 KB
  Не все ключи и таблицы замен обеспечивают максимальную стойкость шифра. Исчерпывающий ответ на вопрос о критериях качества ключей и таблиц замен ГОСТа если и можно получить то только у разработчиков алгоритма. Очевидно что нулевой ключ и тривиальная таблица замен по которой любое значение заменяется но него самого являются слабыми. Таблица замен является долговременным ключевым элементом т.
28580. Криптоанализ 12.62 KB
  В частности полнораундовый алгоритм ГОСТ 2814789 может быть вскрыт с помощью дифференциального криптоанализа на связанных ключах но только в случае использования слабых таблиц замен. 24раундовый вариант алгоритма в котором отсутствуют первые 8 раундов вскрывается аналогичным образом при любых таблицах замен однако сильные таблицы замен делают такую атаку абсолютно непрактичной. [править] Критика ГОСТа Основные проблемы ГОСТа связаны с неполнотой стандарта в части генерации ключей и таблиц замен. Тривиально доказывается что у ГОСТа...