Потоковый ввод/вывод дисковых файлов. Запись и чтение данных при форматированном (текстовом) вводе/выводе
Потоковый ввод/вывод дисковых файлов
Большинству программ требуется сохранять данные на диске и считывать их. Работа с дисковыми файлами подразумевает наличие еще одного набора специальных классов: ifstream для ввода и ofstream для вывода. Класс fstream осуществляет и ввод, и вывод. Объекты этих классов могут быть ассоциированы с диско- выми файлами, а их методы — использоваться для обмена данными с ними.
Вернемся к рис. 12.1. На нем видно, что класс ifstream является наследником класса istream, ofstream — класса ostream, fstream — класса iostream. Эти родитель- ские классы, в свою очередь, являются наследниками класса ios. Такая иерархия вполне логична — классы, ориентированные на работу с файлами, могут ис- пользовать методы более общих классов. К тому же файловые классы использу- ют принцип множественного наследования, будучи наследниками еще и класса fstreambase. Этот класс содержит объект класса filebuf, являющегося файловым буфером, а также ассоциированные методы, унаследованные от более общего класса streambuf. Обычно программисту не приходится заботиться об этих бу- ферных классах.
Классы ifstream, ofstream и fstream объявлены в файле FSTREAM. Программисты на C наверняка обратят внимание на то, что подход к диско- вому вводу/выводу в C++ оказывается совсем иным. Старые функции языка С, такие, как fread() и fwrite() в C++, конечно, работают, но они не так хорошо впи- сываются в концепцию объектно-ориентированной среды программирования. Новый подход, предлагаемый C++, гораздо прозрачнее и проще в использова- нии. Кстати говоря, остерегайтесь случайного перемешивания старых функций С с потоками C++. Они не всегда в хороших отношениях друг с другом, хотя есть возможность заставить их жить дружно.
Форматированный файловый ввод/вывод
При форматированном вводе/выводе числа хранятся на диске в виде серии сим- волов. Таким образом, число 6,02 вместо того, чтобы храниться в виде четырех- байтного значения типа float или восьмибайтного double, хранится в виде после- довательности символов '6', ',', '0', '2'. Это странно с точки зрения экономии памяти, особенно в случае многоразрядных чисел, но зато легко применяется на практике и в некоторых ситуациях гораздо удобнее. Слава Богу, что хоть симво- лы и строки хранятся в файлах в более или менее привычной форме.
Запись данных
Следующая программа демонстрирует запись символа, целого числа, числа типа double и двух объектов типа string в дисковый файл. Вывод на экран не произво- дится. Приведем листинг программы FORMATO.
Листинг 12.2. Программа FORMAT)
// formato.cpp
// Форматированный вывод в файл с использованием <<
#include <fstream> // для файлового ввода/вывода
#include <iostream>
#include <string>
using namespace std;
int main()
{
char ch = 'x';
int j = 77;
double d = 6.02;
string str1 = "Kafka"; // строки без
string str2 = "Proust"; // пробелов
ofstream outfile("fdata.txt"); //создать объект ofstream
outfile << ch // вставить (записать) данные
<< j
<< ' ' // пробелы между числами
<< d
<< str1
<< ' ' // пробелы между строками
<< str2;
cout << "Файл записан\n";
return 0;
}
Здесь мы определили объект outfile в качестве компонента класса ofstream. В то же время мы инициализировали его файлом FDATA.TXT. Инициализация резервирует для дискового файла с данным именем различные ресурсы и полу- чает доступ (или открывает файл) к нему. Если файл не существует, он созда- ется. Если файл уже существует, он переписывается — новые данные в нем заменяют старые. Объект outfile ведет себя подобно cout из предыдущих про- грамм, поэтому можно использовать операцию вставки (<<) для вывода пере- менных любого из стандартных типов в файл. Это так замечательно работает потому, что оператор вставки перегружен в классе ostream, который является родительским для ofstream.
Когда программа завершается, объект outfile вызывает свой деструктор, кото- рый закрывает файл, так что нам не приходится делать это явным образом.
Есть несколько потенциальных проблем с форматированным выводом в дис- ковые файлы. Во-первых, надо разделять числа (77 и 6,02, например) нечисло- выми символами. Поскольку они хранятся в виде последовательности симво- лов, а не в виде полей фиксированной длины, это единственный шанс узнать при извлечении, где кончается одно и начинается другое число. Во-вторых, меж- ду строками должны быть разделители — по тем же причинам. Это подразуме- вает, что внутри строки не может быть пробелов. В этом примере для разделе- ния данных мы использовали пробел в обоих случаях. Радует то, что символы не нуждаются в разделителях, хотя они и являются данными фиксированной длины.
Посмотреть на результаты работы программы FORMATO можно, открыв файл FDATA.TXT с помощью программы WORDPAD или команды DOS TYPE.
Чтение данных
Прочитать файл, созданный программой FORMATO, можно с использованием объ- екта типа ifstream, инициализированного именем файла. Файл автоматически откры- вается при создании объекта. Затем данные из него можно считать с помощью оператора извлечения (>>).
Приведем листинг программы FORMATI, которая считывает данные из файла FDATA.TXT.
Листинг 12.3. Программа FORMATI
// formati.cpp
// форматированное чтение из файла с помощью >>
#include <fstream> // для файлового ввода/вывода
#include <iostream>
#include <string>
using namespace std;
int main()
{
char ch;
int j;
double d;
string str1;
string str2;
ifstream infile("fdata.txt"); // создать объект ifstream
// извлечь (прочесть) из него данные
infile >> ch >> j >> d >> str1 >> str2;
cout << ch << endl // вывести данные
<< j << endl
<< d << endl
<< str1 << endl
<< str2 << endl;
return 0;
}
Объект типа ifstream, который мы назвали infile, действует примерно так же, как cin в предыдущих программах. Если мы корректно вставляли данные в файл, то извлечь их не составит никаких проблем. Мы просто сохраняем их в соответст- вующих переменных и выводим на экран. Результаты работы программы:
х
6.02
Kafka
Proust
Разумеется, числа приводятся обратно к своему двоичному представлению, чтобы с ними можно было работать в программе. Так, 77 сохраняется в пере- менной j типа int, это уже теперь не две семерки символьного типа. 6,02 сохра- няется в переменной типа double.
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | Поиск по сайту:
|