2009-06-24 5 views
15

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

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

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

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

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

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

Таким образом, я изменил, и теперь моя петля проверяет файл file.fail(), а не файл.eof(), и я понимаю, что работает HOW(). Мой вопрос: почему он работает именно так? Существуют ли ситуации, когда это желательно? Мне кажется, что как только вы прошли EOF, вы передали EOF, а eof() должен вернуть true.

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

+1

для (int i = 0; i

ответ

15

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

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

В разделе read станице руководства «ВОЗВРАТ СТОИМОСТИ» (курсив мой):

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

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

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

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

EDIT: Вы должны знать, что тестирование против отказа может быть одинаково неправильным по той же причине. Со страницы, на которую вы ссылаетесь на fail(), возвращается, если сбой предыдущей операции. Это означает, что вам необходимо выполнить прочитанную или другую соответствующую операцию перед ее тестированием.

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

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

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