Книга: Разработка приложений в среде Linux. Второе издание

11.2.5. Частичное чтение и запись

11.2.5. Частичное чтение и запись

Хотя обе функции — и read(), и write() — принимают параметр, указывающий, сколько байт нужно прочитать или записать, ни одна из них не гарантирует, что обработает указанное количество байт, даже если не случается никаких ошибок. Простейший пример этого — попытки чтения из обычного файла, который уже позиционирован в конце. Система не может прочитать ни одного байта, но это в то же время не является ошибкой. Вместо этого read() возвращает 0 байт. Точно так же, если текущая позиция находилась в 10 байт от конца файла, и была выполнена попытка прочитать из файла более 10 байт, то прочитано будет ровно 10 байт и вызов read() вернет число 10. Опять-таки это не рассматривается как ошибочная ситуация.

Поведение read() также зависит от того, был ли файл открыт с флагом O_NONBLOCK. Для файлов многих типов O_NONBLOCK не влияет ни на что. Файлы, для которых система может гарантировать завершенность операции в пределах разумного периода времени, всегда блокирует чтение и запись; такие файлы часто называют быстрыми файлами. Это множество файлов включает локальные блочные устройства и обычные файлы. Для других типов файлов, таких как каналы, и символьных устройств вроде терминалов процесс может ожидать другого процесса (или человека), чтобы тот либо выполнил чтение, либо освободил ресурсы системы при обработке запроса на write(). В обоих случаях система не имеет способа знать — будет ли вообще возможно дождаться завершения системного вызова. Когда такие файлы открываются с флагом O_NONBLOCK, то для каждой операции с файлом система просто делает максимум того, что удается сделать немедленно, а затем возвращает управление вызывающему процессу.

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

Чтобы показать конкретный пример чтения и записи файлов, приведем простую реализацию cat. Она копирует стандартный поток ввода (stdin) на стандартный вывод (stdout) до тех пор, пока есть что копировать.

 1: /* cat.с */
 2:
 3: #include <stdio.h>
 4: #include <unistd.h>
 5:
 6: /* Пока есть данные на стандартном входе (fd0), копировать их в
 7:    стандартный выход (fd1). Выйти, когда не будет доступных данных. */
 8:
 9: int main(void) {
10:  char buf[1024];
11:  int len;
12:
13:  /* len будет >= 0, пока доступны данные
14:     и read() успешен */
15:  while ((len = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
16:   if (write(1, buf, len) != len) {
17:    perror("write");
18:    return 1;
19:   }
20:  }
21:
22:  /* len будет <= 0; если len = 0, больше нет
23:     доступных данных. Иначе - ошибка. */
24:  if (len < 0) {
25:   perror("read");
26:   return 1;
27:  }
28:
29:  return 0;
30: }

Оглавление книги


Генерация: 1.731. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз