Литмир - Электронная Библиотека
A
A

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

148
{"b":"847443","o":1}