Почему std::fstream устанавливает бит EOF именно так?

StackOverflow https://stackoverflow.com/questions/1039667

  •  22-07-2019
  •  | 
  •  

Вопрос

Недавно я столкнулся с проблемой, вызванной использованием fstream::eof().Я прочитал следующую строку из здесь:

Функция eof() возвращает true, если достигнут конец связанного входного файла, в противном случае — false.

и (ошибочно) предположил, что это означает, что если я использую fstream::read() и прочитаю конец файла, функция eof() сообщит мне об этом.Итак, я сделал что-то вроде этого (очень обобщенно):

for(int i = 0; i < max && !file.eof(); i++)
{
     file.read(mything, sizeof(mything));
}

Проблема возникла из-за того, что объясняется позже на странице, указанной выше (которую я изначально не смог прочитать из-за вводящего в заблуждение первого абзаца):

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

Итак, я изменился, и теперь мой цикл проверяет file.fail(), а не file.eof(), и я понимаю, КАК работает eof().Мой вопрос: почему это работает именно так?Есть ли ситуации, когда это желательно?Мне кажется, что как только вы передали EOF, вы передали EOF, и eof() должен вернуть true.

ОБНОВЛЯТЬСпасибо за ответы, думаю, я понял.Единственная операция, которую я выполняю, — это read(), и я сразу проверяю наличие ошибки(), так что думаю, что со мной все в порядке.Теперь мой вопрос в том, что бы Я использую eof() для?

Это было полезно?

Решение

Потому что таким образом он может обнаружить EOF не зная, насколько велик файл.Все, что ему нужно сделать, это просто попытаться прочитать, и если чтение непродолжительное (но не с ошибкой), значит, вы достигли конца файла.

Это отражает функциональность read системный вызов, который обычно вызывает файловый ввод-вывод (материалы Win32 могут вызывать ReadFile но я считаю, что функционал аналогичен).

Из read Раздел man-страницы «ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ» (выделено мной):

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

КСТАТИ:хороший способ написать то, что вы хотите, будет выглядеть так:

T something;
while(file.read(something, sizeof(something))) {
    // process your 'something'
}

это работает, потому что file.read (как и многие члены iostream) возвращают ссылку на сам iostream.Во всех из них есть перегруженный оператор, позволяющий проверить состояние потока.Аналогично читать из std::cin, while(std::cin >> x) { ... } работает также.

РЕДАКТИРОВАТЬ: вы должны знать, что тестирование vs.неудача может быть одинаково неправильной по той же причине.Со страницы, на которую вы дали ссылку fail() возвращается, если предыдущая операция не удалась. Это означает, что вам необходимо выполнить чтение или другую соответствующую операцию перед тестированием.

Другие советы

int n;
std::cin >> n >> std::stripws;

исправляет эту проблему.в этот момент вы можете использовать либо .good(), либо .eof().Мне нравится использовать .good(), так как если на диске есть плохой блок, .good() его обнаружит.но это я..eof () не будет, вам также придется добавить .fail () || .плохой().

Я узнал об этом только после тщательного исследования проблемы употребления пробелов.Я собирался предложить ECO для iostream и ifstream, и о чудо, это уже было сделано.:-D

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top