Проверка EOF при использовании функции read()
Я впервые работаю с чтением из файловых дескрипторов, и я тестирую методом проб и ошибок уже около 3 часов, и у меня почти работает мой читатель! Мне просто нужно немного помочь в проверке EOF на именованном канале.
Итак, я открываю (хорошо несколько) именованный канал, как это:
fds[j].fd = open(pipeNameo, O_RDWR) ; // storing it into my file descriptor array
затем я опрашиваю именованные каналы, чтобы узнать, прошло ли что-нибудь (опрос находится в цикле):
int ret = poll(fds, numOfPipesUsed, timeout_msecs);
И когда что-то происходит, я обрабатываю файл, отправляя дескриптор файла, который был записан, в эту функцию:
int processFileDes( int fd )
{
char buf[10] ;
read(fd, buf, 1) ;
char curr = buf[0] ;
while (curr != EOF)
{
if ( curr == ' ')
{
// do nothing it is a space
}
else if ( curr == '\n')
{
printf("NEW LINE!\n") ;
}
else
{
int num = curr - '0' ; // turns char number into an int
printf("Curr Num: %d\n", num) ;
}
printf("BEFORE\n"); // Gets stuck here when EOF, this is the string of output
read(fd, buf, 1) ;
printf("AFTER\n") ;
curr = buf[0] ;
}
printf("Success!\n") ; // this is never printed
return 0 ;
}
Все отлично работает, кроме read()
Функция застревает (я ожидаю возврата), как только все символы уже прочитаны. Где EOF должен быть. Мне нужно иметь возможность проверить EOF .
Я попробовал обходной путь, который остановил мою программу от чтения, посчитав количество прочитанных символов (так как я знаю размер ввода), и это сработало бы, единственное, что после пробела после последнего символа он вызывает мой цикл опрос, чтобы вернуть 1 и запустить processFile()
снова на оставшихся пробелах (не допустимый ввод) осталось прочитать.
Пожалуйста помоги:')
Ввод - это просто матрица чисел, подобная этой:
0 1 1
2 0 3
1 0 0
3 ответа
Вам нужно открыть неблокирование, так как канал будет ждать, пока данные станут доступны:
fds[j].fd = open(pipeNameo, O_RDWR | O_NONBLOCK);
Сначала вы должны убедиться, что вы на самом деле попали в конец файла в канале.
Когда вы открываете FIFO (другое имя для именованного канала) для чтения, процесс будет ждать, пока другой процесс откроет его для записи и что-то напишет. Затем он будет продолжать ждать ввода, пока все процессы, у которых он открыт для записи, не закроют его.
Вы можете проверить это в нескольких терминальных окнах, используя mkfifo
а также cat
:
$ mkfifo test-fifo
$ cat test-fifo # This is the reading process and will wait for data to read
В другом терминале:
$ cat > test-fifo # This is the writing process; type here and see it above
Теперь, если вы закроете процесс записи, процесс чтения прекратится, потому что он достиг конца файла.
Однако, если вы откроете два процесса записи и выйдете только из одного, FIFO останется открытым и конец чтения не закончится, пока вы не закроете оба из них.
Таким образом, одна возможность, которую очень легко совершить, - это оставить FIFO открытым для записи где-нибудь, чтобы конец чтения никогда не получал конец файла. С одной стороны, следует с осторожностью относиться к тому, что сам этот процесс также имеет FIFO, открытый для записи, или если какой-либо процесс, создавший данные, просто сохраняет канал открытым, а не закрывает его после завершения.
Если вы не можете определить, открыт ли канал для записи, попробуйте fuser
или же lsof
определить любые процессы, которые могут иметь его открытым.
Некоторые другие комментарии к вашему коду, которые также могут быть проблемами:
char buf[10] ;
read(fd, buf, 1) ;
char curr = buf[0] ;
while (curr != EOF)
Это не то, как вы определяете, достигли ли вы конца файла, используя низкоуровневый небуферизованный read
примитивный; это то, как вы делаете это с буферизованной операцией Stdio как fgetc
, С read
Вы вызываете его с желаемой длиной для чтения, и он возвращает, сколько он может прочитать (что может быть меньше, чем запрашиваемая вами длина), 0, если он находится в конце файла, и -1 в случае ошибки. Если вы не проверяете возвращаемое значение read
, у вас есть ошибка. Обратите внимание, что не все ошибки являются фатальными.
Даже если вы использовали fgetc
этот код глючит. fgetc
возвращает int, а не char, чтобы он мог возвращать полный диапазон значений символов, а также значение Sentinel для EOF.
printf("BEFORE\n"); // Gets stuck here when EOF, this is the string of output
read(fd, buf, 1) ;
printf("AFTER\n") ;
Обычно вы не должны пытаться прочитать один и тот же файловый дескриптор дважды между вызовами на опрос; в противном случае второй может блокироваться, если в дескрипторе файла больше нет доступных данных. Вместо этого вы должны сделать одно чтение определенного количества данных, но будьте готовы к read
вернуть меньше данных, чем вы запрашивали, и вернуться к вашему циклу опроса, чтобы выяснить, какие данные теперь доступны (возможно, на другом fd, если на этом нет новых данных, а на другом есть).
Способ использования read
обычно для чтения всего буфера за раз, а не одного символа за раз.