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

ifstream ifs;

// ...

ifs >> foo; // не выполнено: для потока its не открыт ни один файл

// ...

ifs.open(name,ios_base::in); // открываем файл, имя которого задано

                             // строкой name

// ...

ifs.close(); // закрываем файл

// ...

ifs >> bar;  // невыполнено: файл, связанный с потоком ifs, закрыт

// ...

В реальной программе возникающие проблемы, как правило, намного труднее. К счастью, мы не можем открыть файловый поток во второй раз, предварительно его не закрыв. Рассмотрим пример.

fstream fs;

fs.open("foo", ios_base::in);  // открываем файл для ввода

                               // пропущена функция close()

fs.open("foo", ios_base::out); // невыполнено: поток ifs уже открыт

if (!fs) error("невозможно");

Не забывайте проверять поток после его открытия.

Почему допускается явное использование функций

open()
и
close()
? Дело в том, что иногда время жизни соединения с файлом не ограничивается его областью видимости. Однако это событие происходит так редко, что о нем можно не беспокоиться. Более важно то, что такой код можно встретить в программах, в которых используются стили и идиомы языков и библиотек, отличающихся от стилей и идиом, используемых в потоках
iostream
(и в остальной части стандартной библиотеки C++).

Как будет показано в главе 11, о файлах можно сказать намного больше, но сейчас нам достаточно того, что их можно использовать в качестве источников и адресатов данных. Это позволяет нам писать программы, которые были бы нереалистичными, если бы предложили пользователю непосредственно вводить с клавиатуры всю входную информацию. С точки зрения программиста большое преимущество файла заключается в том, что мы можем снова прочитать его в процессе отладки, пока программа не заработает правильно.

10.5. Чтение и запись файла

Посмотрим, как можно было бы считать результаты некоторых измерений из файла и представить их в памяти. Допустим, в файле записана температура воздуха, измеренная на метеостанции.

0 60.7

1 60.6

2 60.3

3 59.22

...

Этот файл содержит последовательность пар (час, температура). Часы пронумерованы от

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

Представим информацию в виде структуры

Reading
.

struct Reading {      // данные о температуре воздуха

  int hour;           // часы после полуночи [0:23]

  double temperature; // по Фаренгейту

  Reading(int h, double t) :hour(h), temperature(t) { }

};

В таком случае данные можно считать следующим образом:

vector<Reading> temps; // здесь хранится считанная информация

int hour;

double temperature;

while (ist >> hour >> temperature) {

  if (hour < 0 || 23 <hour) error("Некорректное время");

  temps.push_back(Reading(hour,temperature));

}

Это типичный цикл ввода. Поток

istream
с именем
ist
мог бы быть файловым потоком ввода (
ifstream
), как в предыдущем разделе, стандартным потоком ввода (
cin
) или любым другим потоком
istream
. Для кода, подобного приведенному выше, не имеет значения, откуда поток
istream
получает данные. Все, что требуется знать нашей программе, — это то, что поток
ist
относится к классу
istream
и что данные имеют ожидаемый формат. Следующий раздел посвящен интересному вопросу: как выявлять ошибки в наборе входных данных и что можно сделать после выявления ошибки форматирования.

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

ofstream
) из предыдущего раздела наравне с любым другим потоком
ostream
.

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

for (int i=0; i<temps.size(); ++i)

  ost << '(' << temps[i].hour << ',' << temps[i].temperature << ")\n";

Затем итоговая программа прочитала бы исходные данные из файла и создала новый файл в формате (час, температура).

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Поскольку файловые потоки автоматически закрывают свои файлы при выходе из области видимости, полная программ принимает следующий вид:

#include "std_lib_facilities.h"

struct Reading {      // данные о температуре воздуха

  int hour;           // часы после полуночи [0:23]

  double temperature; // по Фаренгейту

  Reading(int h, double t):hour(h), temperature(t) { }

};

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