My_type var;
while (ist>>var) { // читаем до конца файла
// тут можно было бы проверить,
// является ли переменная var корректной
// тут мы что-нибудь делаем с переменной var
}
// выйти из состояния bad удается довольно редко;
// не делайте этого без крайней необходимости:
if (ist.bad()) error(" плохой поток ввода ");
if (ist.fail()) {
// правильно ли выполнен ввод ?
}
// продолжаем: обнаружен конец файла
Иначе говоря, мы считываем последовательность значений, записывая их переменные, а когда не можем больше считать ни одного значения, проверяем состояние потока, чтобы понять, что случилось. Как показано в разделе 10.6, эту стратегию можно усовершенствовать, заставив поток
istream
генерировать исключение типа failure в случае сбоя. Это позволит нам не постоянно выполнять проверку.
// где-то: пусть поток ist генерирует исключение при сбое
ist.exceptions(ist.exceptions()|ios_base::badbit);
Можно также назначить признаком завершения ввода (terminator) какой-нибудь символ.
My_type var;
while (ist>>var) { // читаем до конца файла
// тут можно было бы проверить,
// является ли переменная var корректной
// тут мы что-нибудь делаем с переменной var
}
if (ist.fail()) { // в качестве признака завершения ввода используем
// символ '|' и / или разделитель
ist.clear();
char ch;
if (!(ist>>ch && ch=='|'))
error(" неправильное завершение ввода ");
}
// продолжаем: обнаружен конец файла или признак завершения ввода
Если вы не хотите использовать в качестве признака завершения ввода какой-то символ, т.е. хотите ограничиться только признаком конца файла, то удалите проверку перед вызовом функции
error()
. Однако признаки завершения чтения оказываются очень полезными, когда считываются файлы с вложенными конструкциями, например файлы с помесячной информацией, содержащей ежедневную информацию, включающую почасовую информацию, и т.д. В таких ситуациях стоит подумать о символе завершения ввода.
К сожалению, этот код остается довольно запутанным. В частности, слишком утомительно при считывании многих файлов каждый раз повторять проверку символа завершения ввода. Для решения этой проблемы следует написать отдельную функцию.
// где-то: пусть поток ist генерирует исключение при сбое
ist.exceptions(ist.exceptions()|ios_base::badbit);
void end_of_loop(istream& ist, char term, const string& message)
{
if (ist.fail()) { // используем символ завершения ввода
// и/или разделитель
ist.clear();
char ch;
if (ist>>ch && ch==term) return; // все хорошо
error(message);
}
}
Это позволяет нам сократить цикл ввода.
My_type var;
while (ist>>var) { // читаем до конца файла
// тут можно было бы проверить, является ли переменная var
// корректной
// тут мы что-нибудь делаем с переменной var
}
end_of_loop(ist,'|'," неправильное завершение файла "); // проверяем,
// можно ли
// продолжать
// продолжаем: обнаружен конец файла или признак завершения ввода
Функция
end_of_loop()
не выполняет никаких действий, кроме проверки, находится ли поток в состоянии
fail()
. Мы считаем, что эту достаточно простую и универсальную функцию можно использовать для разных целей.
10.11. Чтение структурированного файла
Попробуем применить этот стандартный цикл в конкретном примере. Как обычно, используем этот пример для иллюстрации широко распространенных методов проектирования и программирования. Предположим, в файле записаны результаты измерения температуры, имеющие определенную структуру.
• В файле записаны годы, в течение которых производились измерения.
• Запись о годе начинается символами
{ year
, за которыми следует целое число, обозначающее год, например 1900, и заканчивается символом
}
.
• Год состоит из месяцев, в течение которых производились измерения.
• Запись о месяце начинается символами
{ month
, за которыми следует трехбуквенное название месяца, например jan, и заканчивается символом
}
.
• Данные содержат показания времени и температуры.
• Показания начинаются с символа
(
, за которыми следует день месяца, час дня и температура, и заканчиваются символом
)
.
{ year 1990 }
{year 1991 { month jun }}
{ year 1992 { month jan ( 1 0 61.5) } {month feb (1 1 64) (2 2
65.2)}}
{year 2000