Проверка 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 обычно для чтения всего буфера за раз, а не одного символа за раз.

Возвращаемое значение 0 из read указывает EOF.

Другие вопросы по тегам