2012-01-23 18 views
14

Рассмотрим следующую строку кода:чтения() из стандартного ввода

while((n = read(STDIN_FILENO, buff, BUFSIZ)) > 0) 

Согласно моему пониманию read/write функции являются частью небуферизованного ввода/вывода. Значит ли это, что функция read() будет читать только один символ за звонок из stdio? Или, другими словами, значение п будет

-1 in case of error 
n = 0 in case of EOF 
    1 otherwise 

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

Примечание: Я также думал, что read() будет ждать, пока он успешно прочитает BUFSIZ количество символов из stdin. Но что происходит в случае, количество символов, доступных для чтения, меньше BUFSIZ? Будет ли читать навсегда или до тех пор, пока EOF не прибудет (Ctrl + D по unix или Ctrl + Z на окнах)?

Также, скажем BUFSIZ = 100 и stdin = ACtrl+D (т.е. EOF сразу после одного символа). Теперь сколько раз while loop будет перебирать?

+2

Как FYI, я считаю, что вы можете 'читать' от' 0', что является стандартным вводом, но может использовать только 'stdin' с' fread() '. –

+0

да, ну, прямо ... thnx !! Поскольку stdin имеет тип 'FILE *', он не может использоваться с 'read' –

+3

или' STDIN_FILENO', если вы настроены на маркировку. – Dave

ответ

2

Как read() Manpage состояний:

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

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

Таким образом, каждый read() будет читать до числа указанных байт; но он может читать меньше. «Без буферизации» означает, что если вы укажете read(fd, bar, 1), чтение будет читать только один байт. Буферизованный IO пытается читать в квантах BUFSIZ, даже если вам нужен только один символ. Это может показаться расточительным, но это позволяет избежать накладных расходов на выполнение системных вызовов, что делает его быстрым.

+0

вы ответ слишком общий ... любезно будьте более конкретным для проблемы –

0
  1. читать попытки получить все запрошенные символы.
  2. Если EOF случается до того, как все запрошенные символы могут быть возвращены, он возвращает то, что получил после того, как это произойдет, следующее чтение возвращает -1, чтобы вы знали, что вы закончили файл.

Что происходит, когда он пытается читать, и в нем нет ничего, что связано с блокировкой. Вы можете вызвать open, чтобы прочитать блокировку или неблокирование файла. «Блокировка» означает ждать, пока что-то вернется.

Это то, что вы видите в оболочке, ожидающей ввода. Он сидит там. Пока ты не вернешься.

Неблокирующее средство, которое будет читать без байтов данных, если их нет.В зависимости от множества других факторов, которые могли бы сделать совершенно правильный ответ непригодным для вас, read установит errno на что-то вроде EWOULDBLOCK, которое позволит вам узнать, почему ваше чтение вернуло нулевые байты. Это не обязательно фатальная ошибка.

Ваш код может проверить минус найти EOF или ошибки

17

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

Если чтение() считывается с терминала в каноническом/приготовленном режиме, драйвер tty предоставляет данные по строке за раз. Поэтому, если вы скажете read(), чтобы получить 3 символа или 300, чтение будет зависать, пока драйвер tty не увидит новую строку или определенный ключ EOF терминала, а затем read() вернется либо с количеством символов в строке, либо с помощью количество запрошенных вами символов, в зависимости от того, что меньше.

Если чтение() считывается с терминала в неканоническом/необработанном режиме, чтение будет иметь доступ к нажатиям клавиш сразу. Если вы попросите read() получить 3 символа, он может вернуться с нулем от 0 до 3 символов в зависимости от времени ввода и настройки терминала.

read() будет вести себя по-разному перед лицом сигналов, возвращаясь с меньшим, чем запрашиваемое число символов, или -1 с errno, установленным в EINTR, если сигнал прервал чтение до появления каких-либо символов.

read() будет вести себя по-другому, если дескриптор настроен для неблокирующего ввода-вывода. read() вернет -1 с errno, установленным в EAGAIN или EWOULDBLOCK, если вход не был немедленно доступен. Это относится к сокетам.

Как вы можете видеть, вы должны быть готовы к неожиданностям, когда вы вызываете read(). Вы не всегда получите количество запрошенных вами символов, и вы можете получить нефатальные ошибки, такие как EINTR, что означает, что вы должны повторить чтение().

+0

ohh ... на самом деле я пропустил набранную скобку ... thnx !! –

+0

теперь возвращаются к актуальной проблеме. –

3

Ваш код гласит:

while((n = read(0, buff, BUFSIZ) != 0)) 

Это испорчено - круглые скобки означают, что интерпретируется как:

while ((n = (read(0, buff, BUFSIZ) != 0)) != 0) 

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

Вы должны написать:

while ((n = read(0, buff, BUFSIZ)) > 0) 

Это останавливается на EOF или ошибки чтения и n позволяет узнать, какие условия вы столкнулись.


Видимо, код, указанный выше, был опечаткой в ​​вопросе.

Небуферизованный ввод-вывод будет считывать число символов, которые вы читаете (но не более). Он может читать меньше за счет EOF или ошибки. Он также может читать меньше, потому что меньше времени доступно во время разговора. Рассмотрим терминал; как правило, это будет читать только до конца строки, потому что нет более доступного, чем это. Рассмотрим трубу; если процесс подачи генерировал 128 непрочитанных байтов, тогда, если BUFSIZ равен 4096, вы получите только 128 байтов от чтения.Неблокирующий файловый дескриптор может вернуться, потому что ничего не доступно; сокет может вернуть меньшее количество байтов, поскольку пока еще нет информации; чтение диска может возвращать меньшее количество байтов, потому что в процессе чтения выполняется меньше запрашиваемого количества байтов, оставшихся в файле.

В общем случае read() не вернет только один байт, если вы запросите много байтов.

+0

это была опечатка ... я ее исправил ... теперь возвращаюсь к реальной проблеме. –

0

Когда мы говорим, что read не буферизирован, это означает, что на уровне вашего процесса не происходит буферизация после того, как данные извлекаются из описания открытого файла, который является потенциально разделяемым ресурсом. Если stdin является терминалом, то, скорее всего, по крайней мере, 2 дополнительных буферов в комбинации, однако:

  1. Терминал буфера, который, вероятно, может содержать 1-4k данных от линии до.
  2. Буфер с готовым/каноническим режимом ядра для ввода/редактирования строки на терминале, который позволяет пользователю выполнять примитивное редактирование (backspace, backword, erase line и т. Д.) В строке до его отправки (в буфер, описанный выше) нажав enter.

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

Смежные вопросы