Как feof () на самом деле знает, когда достигнут конец файла?

Я новичок в C++ и пытаюсь лучше понять feof(). Я читал это feof() флаг установлен в true только после попытки прочитать конец файла так много раз новички будут читать еще раз, чем они ожидали, если они сделают что-то вроде while(!feof(file)). Однако я пытаюсь понять, как он на самом деле интерпретирует попытку прочитать конец файла? Является ли весь файл уже прочитанным и количество символов уже известно или там какой-то другой механизм работает?

Я понимаю, что это может быть дубликат вопроса где-то, но я не смог его найти, вероятно, потому, что я не знаю лучшего способа выразить то, что я прошу. Если ответ уже есть, ссылка будет очень признательна. Спасибо.

5 ответов


что бы еще ни делала библиотека C++, в конечном итоге она должна читать из файла. Где-то в операционной системе есть фрагмент кода, который в конечном итоге обрабатывает это чтение. Он получает из файловой системы длину файла, хранящегося так же, как файловая система хранит все остальное. Зная длину файла, положение считываемого файла и количество считываемых байтов, можно определить, что чтение низкого уровня попадает в конец файла.

когда это решение принято,оно передается по стопке. В конце концов, он попадает в стандартную библиотеку, которая записывает внутри, что конец файла достигнут. Когда запрос на чтение в библиотеку пытается пройти мимо этого записанного конца, флаг EOF установлен и feof начнет возвращать true.


feof() является частью стандартной библиотеки C амортизированный I / O. поскольку он буферизован,fread() предварительно считывает некоторые данные (наверняка не весь файл, однако). Если при буферизации fread() обнаруживает EOF (базовая процедура OS возвращает специальное значение, обычно -1), Он устанавливает флаг на FILE структура. feof() просто проверяет наличие этого флага. Так что feof() возврат true по существу означает " предыдущая попытка чтения обнаруженного конца папка."

как EOF обнаружен для OS/FS и не имеет ничего общего с библиотекой/языком C. ОС имеет некоторый интерфейс для чтения данных из файлов. Библиотека C - это просто мост между ОС и программой, поэтому вам не нужно менять программу, если вы переходите на другую ОС. ОС знает, как файлы хранятся в его файловой системе, поэтому она знает, как обнаружить EOF. Я предполагаю, что обычно это выполняется путем сравнения текущей позиции с длина файла, но это может быть не так просто и может включать в себя много деталей низкого уровня (например, что, если файл находится на сетевом диске?).

интересный вопрос заключается в том, что происходит, когда поток находится в конце, но он еще не был обнаружен ни одним чтением. Например, если открыть пустой файл. Делает первый вызов feof() перед любым fread() вернуть true или false? Ответ, вероятно, ложен. документы не очень ясно об этом тема:

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

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


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


как feof () на самом деле знает, когда достигнут конец файла?

когда код пытается прочитать принят последний символ.

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


пример кода, демонстрирующий feof() переход от 0 к 1

#include <stdio.h>

void ftest(int n) {
  FILE *ostream = fopen("tmp.txt", "w");
  if (ostream) {
    while (n--) {
      fputc('x', ostream);
    }
    fclose(ostream);
  }
  FILE *istream = fopen("tmp.txt", "r");
  if (istream) {
    char buf[10];
    printf("feof() %d\n", feof(istream));
    printf("fread  %zu\n", fread(buf, 1, 10, istream));
    printf("feof() %d\n", feof(istream));
    printf("fread  %zu\n", fread(buf, 1, 10, istream));
    printf("feof() %d\n", feof(istream));
    puts("");
    fclose(istream);
  }
}

int main(void) {
  ftest(9);
  ftest(10);
  return 0;
}

выход

feof() 0
fread  9  // 10 character read attempted, 9 were read
feof() 1  // eof is set as previous read attempted to read passed the 9th or last char
fread  0
feof() 1

feof() 0
fread  10  // 10 character read attempted, 10 were read
feof() 0   // eof is still clear as no attempt to read passed the 10th, last char
fread  0
feof() 1

на feof() функция устанавливает конец индикатора файла при считывании символа EOF. Так когда feof() читает последний элемент, EOF сначала не читается вместе с ним. Так как индикатор EOF не установлен и feof() возвращает ноль, поток снова входит в цикл while. На этот раз fgets узнает, что следующий символ-EOF, его отбрасывает и возвращает NULL, но также устанавливает индикатор EOF. Так что feof() обнаруживает индикатор конца файла и возвращает ненулевое значение, поэтому ломать цикл while.