ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ В C++ (4-Е ИЗДАНИЕ) (часть 12) онлайн

Строки с пробелами

Подход, продемонстрированный в последнем примере, не позволяет обрабаты-

вать строки с char*, содержащие пробелы. Для того чтобы эта ситуация измени-

лась, после каждой строки нужно писать специальный символ-ограничитель и

использовать функцию getline() вместо оператора извлечения. Наша следующая

маленькая программа OLINE выводит строки с пробелами. Посмотрите, как это

сделано.

Листинг 12.4. Программа OLINE

// oline.cpp

// файловый вывод строк с пробелами

#include <fstream>              // для операций

                                // файлового ввода/вывода

using namespace std;

 

int main()

{

  ofstream outfile("TEST.TXT"); // создать выходной файл

                                // отправить текст в файл

  outfile << "Приходит март. Я сызнова служу.\n";

  outfile << "В несчастливом кружении событий \n";

  outfile << "изменчивую прелесть нахожу \n";

  outfile << "в смешеньи незначительных наитий.\n";

  return 0;

}

 

Когда вы запустите программу, строки стихотворения И. Бродского будут

записаны в файл. Каждая строка заканчивается символом разделения строк ('\n').

Обратите внимание, это строки типа char*, а не объекты класса string. Многие

потоковые операции гораздо легче производить с этим типом данных.

Чтобы извлечь строки из файла, мы создадим ifstream и станем читать строч-

ку за строчкой функцией getline(), которая является методом класса istream. Эта

функция считывает все символы, включая разделители, пока не дойдет до спе-

циального символа '\n', затем помещает результат чтения в буфер, переданный

ей в качестве аргумента. Максимальный размер буфера передается с помощью

второго аргумента. Его содержимое выводится на экран после считывания каж-

дой строки.

Листинг 12.5. Программа ILINE

// iline.cpp

// Файловый ввод (извлечение из файла) строк

#include <fstream>             // для файловых функций

#include <iostream>

using namespace std;

 

int main()

{

  const int MAX = 80;          // размер буфера

  char buffer[MAX];            // буфер символов

  ifstream infile("TEST.TXT"); // создать входной файл

  while( !infile.eof() )       // цикл до EOF

    {

 

    infile.getline(buffer, MAX); // читает строку текста

    cout << buffer << endl;      // и выводит ее

    }

  return 0;

}

В результате работы программы на экране появятся все та же строфа из сти-

хотворения, которую мы записали в файл TEST.TXT в процессе работы програм-

мы OLINE. Программе не дано знать, сколько всего строчек в тексте, поэтому она

продолжает чтение до тех пор, пока не встретит признак окончания файла (EOF).

Учтите, что эту программу нельзя применять для чтения произвольных фай-

лов, — каждая строка текста должна заканчиваться символом '\n'. При попытке

прочитать файл иной структуры программа зависнет.

Определение признака конца файла (EOF)

Итак, объекты порожденных из ios классов содержат флаги статуса ошибок, с по-

мощью которых можно проверить результат выполнения операций. При чтении

файла небольшими порциями, как в этом примере, мы рано или поздно наткнем-

ся на условие окончания файла. Сигнал EOF посылается в программу операцион-

ной системой, когда больше нет данных для чтения. В программе ILINE это усло-

вие встречалось в выражении

 

while( !infile.eof() )    //Пока не EOF

 

Это все замечательно, но надо учитывать, что, проверяя конкретный флаг при-

знака окончания файла, мы не проверяем все остальные флаги ошибок. A failbit

и badbit тоже могут возникнуть при работе программы, хотя это случается до-

вольно редко. Чтобы проверять все, что можно, мы изменим условие цикла:

while( infile.good() )    //Пока нет ошибок

Можно также проверять поток напрямую. Любой потоковый объект, напри-

мер infile, имеет значение, которое может тестироваться на предмет выявления

наиболее распространенных ошибок, включая EOF. Если какое-либо из условий

ошибки имеет значение true, объект возвращает ноль. Если все идет хорошо,

объект возвращает ненулевое значение. Это значение на самом деле является

указателем, но возвращаемый «адрес» никакой смысловой нагрузки не несет —

он просто должен быть нулем либо не нулем. Поэтому запишем еще один вари-

ант цикла while:

while( infile )     //Пока нет ошибок

 

На вид это выражение, конечно, очень простое, но непосвященным, скорее

всего, будет непонятно, что оно делает.

 

20