Шрифт:
Интервал:
Закладка:
10.4. Открытие файла

cout << "Пожалуйста, введите имя файла: ";
string name;
cin >> name;
ifstream ist(name.c_str()); // ist — это поток ввода для файла,
// имя которого задано строкой name
if (!ist) error(" Невозможно открыть файл для ввода ",name);

vector<Point> points;
Point p;
while (ist>>p) points.push_back(p);
Вывод в файлы аналогичным образом можно выполнить с помощью потоков ofstream. Рассмотрим пример.
cout << "Пожалуйста, введите имя файла для вывода: ";
string oname;
cin >> oname;
ofstream ost(oname.c_str()); // ost — это поток вывода для файла,
// имя которого задано строкой name
if (!ost) error("Невозможно открыть файл вывода ",oname);

for (int i=0; i<points.size(); ++i)
ost << '(' << points[i].x << ',' << points[i].y << ")n";
Когда файловый поток выходит из пределов видимости, связанный с ним файл закрывается. Когда файл закрывается, связанный с ним буфер “очищается” (“flushed”); иначе говоря, символы из буфера записываются в файл.
Как правило, файлы в программе лучше всего открывать как можно раньше, до выполнения каких-либо серьезных вычислений. Помимо всего прочего, было бы слишком расточительным выполнить большую часть работы и обнаружить, что вы не можете ее завершить, потому что вам некуда записать результаты.
Открытие файла неявно является частью процесса создания потоков ostream и istream. В идеале при закрытии файла следует полагаться на его область видимости.
Рассмотрим пример.
void fill_from_file(vector<Point>& points, string& name)
{
ifstream ist(name.c_str()); // открываем файл для чтения
if (!ist) error("Невозможно открыть файл для ввода",name);
// ...используем поток ist...
// файл неявно закроется, когда мы выйдем из функции
}

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, а температура измерена по шкале Фаренгейта. Дальнейшее форматирование не предусмотрено; иначе говоря, файл не содержит никаких заголовков (например, информации об источнике данных), единиц измерений, знаков пунктуации (например, скобок вокруг каждой пары значений) или признак конца файла. Это простейший вариант.