Найдите, сколько байтов готовы для чтения из ФАЙЛА * или дескриптора файла - PullRequest
9 голосов
/ 23 марта 2011

Учитывая FILE* или дескриптор файла, есть ли стандартный способ определить, сколько байтов готово для чтения?

Я не могу использовать s=ftell(f),fseek(f,0,SEEK_END),e=ftell(f),fseek(f,s,SEEK_SET),e-s, поскольку FILE* простооборачивая дескриптор файла, который я получил от pipe(2), и получаю ESPIPE, когда я пытаюсь это сделать.приготовьте хотя бы один байт для чтения, а затем читайте байт за раз, пока select(2) не скажет мне остановиться.Это кажется немного неуклюжим и медленным.

Есть ли лучший способ сделать это?

Ответы [ 5 ]

6 голосов
/ 23 марта 2011

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

Поэтому обычным делом является использованиеselect, чтобы определить читаемость, а затем прочитать любой предпочитаемый вами размер буфера.В качестве альтернативы, установите O_NONBLOCK, используя fcntl, и проверьте -1, возвращаемое значение и errno EAGAIN.

4 голосов
/ 23 марта 2011

Это не благословлено никакими современными стандартами, но обычный традиционный способ Unix сделать это с помощью ioctl(fd, FIONREAD, &n); См. Ответы на этот вопрос:

Определить размер трубы без вызова read ()

3 голосов
/ 23 марта 2011

Если вы ищете только что-то более эффективное, чем чтение 1 байта, а не размер доступных данных в FIFO, то вы можете:

  1. Установите дескриптор файла в неблокирующий режим.
  2. Используйте select, чтобы узнать, когда доступны данные
  3. Вызов read с большим буфером. Он может вернуть меньше, чем вы запрашивали ( проверьте код возврата ), или он может вернуть -1 с помощью EAGAIN или EWOULDBLOCK, чтобы указать, что вы должны вернуться к вызову select (данные недоступны )
1 голос
/ 16 июля 2018

Расширение на ответ, данный R ..

Большая реальная программная структура использует ioctl для определения количества байтов, подобных этому (проверка ошибок при отбрасывании):

FreeBSD, Linux и Solaris ( источник ):

int nbytes;
ioctl(fd, FIONREAD, &nbytes);

IRIX ( источник ):

size_t nbytes;
ioctl(fd, FIONREAD, &nbytes);

Windows ( источник ):

long nbytes;
ioctlsocket(fd, FIONREAD, &nbytes);
0 голосов
/ 23 марта 2011

Да. fstat(2). Я взглянул на него раньше и увидел, что он не будет работать на FILE* (именно поэтому я вернулся к анти-шаблону fseek), но не думал, что придется обращаться к файловому дескриптору.

...