Читаем Linux API. Исчерпывающее руководство полностью

Этот фрагмент кода выведет весьма странные данные, поскольку в них, скорее всего, будут включены символы, дополняющие фактически введенную строку. Дело в том, что вызов read() не добавляет завершающий нулевой байт в конце строки, которая задается для вывода функции printf(). Нетрудно догадаться, что именно так и должно быть, поскольку read() может использоваться для чтения любой последовательности байтов из файла. В некоторых случаях входные данные могут быть текстом, но бывает, что это двоичные целые числа или структуры языка C в двоичном виде. Невозможно «объяснить» вызову read() разницу между ними, поэтому он не в состоянии выполнять соглашение языка C о завершении строки символов нулевым байтом. Если в конце буфера входных данных требуется наличие завершающего нулевого байта, его нужно вставлять явным образом:

char buffer[MAX_READ + 1];

ssize_t numRead;

numRead = read(STDIN_FILENO, buffer, MAX_READ);

if (numRead == -1)

errExit("read");

buffer[numRead] = '\0';

printf("The input data was: %s\n", buffer);

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

4.5. Запись в файл: write()

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

#include

ssize_t write(int fd, const void *buffer, size_t count);

Возвращает количество записанных байтов или –1 при ошибке

Аргументы для write() аналогичны тем, что использовались для read(): buffer представляет собой адрес записываемых данных, count является количеством записываемых из буфера данных, а fd содержит дескриптор файла, который ссылается на тот файл, куда будут записываться данные.

В случае успеха вызов write() возвращает количество фактически записанных данных, которое может быть меньше значения аргумента count. Для дискового файла возможными причинами такой частичной записи может оказаться переполнение диска или достижение ограничения ресурса процесса на размеры файла. (Речь идет об ограничении RLIMIT_FSIZE, которое рассматривается в разделе 36.3.)

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

4.6. Закрытие файла: close()

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

#include

int close(int fd);

Возвращает 0 при успешном завершении или –1 при ошибке

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

Как и любые другие системные вызовы, close() должен сопровождаться проверкой кода на ошибки:

if (close(fd) == -1)

errExit("close");

Такой код отлавливает ошибки вроде попыток закрытия неоткрытого дескриптора файла или закрытия одного и того же дескриптора файла дважды. Он также отлавливает сбойные ситуации, диагностируемые конкретной файловой системой в ходе операции закрытия.

Сетевая файловая система — NFS (Network File System) — предоставляет пример такой специфичной для нее ошибки. Когда в NFS происходит сбой завершения транзакции, означающий, что данные не достигли удаленного диска, эта ошибка доходит до приложения в виде сбоя системного вызова close().

4.7. Изменение файлового смещения: lseek()

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

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

Системный вызов lseek() устанавливает файловое смещение открытого файла, на который указывает дескриптор fd, в соответствии со значениями, заданными в аргументах offset и whence.

#include

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных