C : std :: istream проверяет EOF без чтения / потребления токенов / с использованием оператора>>

#c #filestream #iostream #eof

#c #поток файлов #iostream #eof

Вопрос:

Я хотел бы проверить, достигло ли std::istream конца без чтения из него.

Я знаю, что могу проверить EOF следующим образом:

 if (is >> something) 
  

но у этого есть ряд проблем. Представьте, что существует множество, возможно виртуальных, методов / функций, которые ожидают std::istreamamp; передачи в качестве аргумента.
Это означало бы, что я должен выполнять «домашнюю работу» по проверке EOF в каждом из них, возможно, с другим типом something переменной, или создать какую-нибудь странную оболочку, которая обрабатывала бы сценарий вызова методов ввода.

Все, что мне нужно сделать, это:

 if (!IsEof(is)) Input(is);
  

метод IsEof должен гарантировать, что поток не изменен для чтения, так что приведенная выше строка эквивалентна:

 Input(is)
  

что касается данных, считанных в Input методе.

Если нет универсального решения, которое обозначало бы and std::istream , есть ли какой-либо способ сделать это для std::ifstream or cin ?

РЕДАКТИРОВАТЬ: Другими словами, всегда должно выполняться следующее assert :

 while (!IsEof(is)) {
  int something;
  assert(is >> something);
}
  

Комментарии:

1. Перечитывая вопрос, я не уверен, что понял с первого раза. Вы действительно имеете в виду if (IsEof(is)) Input(is) или там должно быть логическое «НЕ»?

2. Логично, что нет. Но что важно, мне нужна проверка без предварительного использования каких-либо токенов (см. Редактирование выше), и вам все будет ясно.

3. После редактирования это утверждение очень сильное. В нем указано, что IsEof должен возвращать false только в том случае, int если форматированное извлечение из, будет успешным. Вы уверены, что это то, что вы имеете в виду? Если это так, вы не можете сделать это с raw istream ; вам понадобится какой-то структурированный кэш, чтобы вы могли прочитать и кэшировать следующий int. В качестве альтернативы вам понадобится способ вернуть все символы, прочитанные при синтаксическом анализе int и std::istream не гарантирует, что это всегда будет возможно.

4. Это int всего лишь пример, я бы хотел, чтобы это работало независимо от того, какой следующий токен, всякий раз, когда достигается EOF. Да, я ищу функцию, которая сообщала бы мне, достиг ли я позиции после последнего токена в потоке (т. Е. EOF), не пытаясь прочитать следующий токен или, по крайней мере, прочитать его заранее и поместить обратно. Возможно ли это?

5. Просто для пояснения, что именно вы подразумеваете под «токеном»? Если вы говорите о произвольно сложных типах, то — предположительно — следующий «токен» может состоять из произвольно большого количества символов, и вам придется попытаться подделать чтение всего объекта. Если это чтение завершится неудачей, вам придется сохранить все, что было прочитано, в кэше (возможно, структурированном, возможно, нет), потому что вы не сможете — в общем — перенести все это обратно в простой istream .

Ответ №1:

Класс istream имеет бит eof, который можно проверить с помощью is.eof() члена.

Редактировать: Итак, вы хотите посмотреть, является ли следующий символ маркером EOF, не удаляя его из потока? if (is.peek() == EOF) вероятно, это то, что вы хотите тогда. Смотрите документацию для istream::peek

Комментарии:

1. Это работает не так, как ожидалось, что-то должно быть прочитано сначала , чтобы eof() заработал. Рассмотрим следующий код: while (IsEof(is)) { int something; assert(is >> что-то); }

Ответ №2:

Это невозможно. Как IsEof функция должна знать, что следующий элемент, который вы собираетесь прочитать, является int?

Следующее также не должно вызывать никаких утверждений?

  while(!IsEof(in))
 {
    int x;
    double y;
    if( rand() % 2 == 0 )
    {
       assert(in >> x);
    } else {
       assert(in >> y);
    }
 }
  

Тем не менее, вы можете использовать exceptions метод, чтобы сохранить «ведение домашнего хозяйства» в одном месте.

Вместо

    if(IsEof(is)) Input(is)
  

попробуйте

    is.exceptions( ifstream::eofbit /* | ifstream::failbit etc. if you like */ )
   try {
     Input(is);
   } catch(const ifstream::failureamp; ) {
   }
  

Это не мешает вам читать, пока не стало «слишком поздно», но это устраняет необходимость иметь if (is >> x), if (is >> y) и т.д. во всех функциях.

Ответ №3:

Обычно,

 if (std::is)
{ 
}
  

этого достаточно. Для получения более точной информации также есть .good(), .bad(), .fail()

Вот справочная ссылка:http://www.cplusplus.com/reference/iostream/istream /

Ответ №4:

Есть веские причины, по которым отсутствует функция isEof: ее трудно указать удобным способом. Например, operator>> обычно начинается с пропуска пробелов (в зависимости от флага), в то время как некоторые другие функции ввода способны считывать пробелы. Как бы вы isEof () справились с ситуацией? Начинать с пропуска пробелов или нет? Будет ли это зависеть от флага, используемого operator>> или нет? Восстановит ли это пробелы в потоке или нет?

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

Ответ №5:

Нет, в общем случае нет способа узнать, достигнет ли eof следующая операция чтения.

Если поток подключен к клавиатуре, условием EOF является то, что я наберу Ctrl Z / Ctrl D в следующем приглашении. Как бы IsEof (is) обнаружил это?

Комментарии:

1. @leden — Нет, у них одинаковый интерфейс. Это всего лишь причина, по которой это работает так, как работает.