На этом шаге мы рассмотрим пример использования потоковых классов для организации доступа к файлам.
Следующая программа открывает файл charset.out и записывает в него текущий набор символов (все символы в интервале 32-255):
//--------------------------------------------------------------------------- #include <vcl.h> #include <string> // Строки #include <iostream> // Ввод-вывод #include <fstream> // Файловый ввод-вывод #include <iomanip> // setw() #include <cstdlib> // exit() #include <conio.h> //необходимо для getch() #pragma hdrstop //--------------------------------------------------------------------------- #pragma argsused using namespace std; std::string ToRus(const std::string &in) { char *buff = new char [in.length()+1]; CharToOem(in.c_str(),buff); std::string out(buff); delete [] buff; return out; } // Опережающие объявления void writeCharsetToFile (const string& filename); void outputFile (const string& filename); int main (int argc, char* argv[]) { writeCharsetToFile("charset.out"); outputFile("charset.out"); cout << ToRus("Работа выполнена"); getch(); return 0; } void writeCharsetToFile (const string& filename) { // Открытие выходного файла ofstream file(filename.c_str()); // Файл открыт? if (! file) { // НЕТ, аварийное завершение программы cerr << ToRus("Не могу открыть файл \"") << filename << "\"" << endl; exit(EXIT_FAILURE); } // Вывод текущего набора символов for (int i=32; i<256; i++) { file << ToRus("Значение: ") << setw(3) << i << " " << ToRus("Символ: ") << static_cast<char>(i) << endl; } } // Автоматическое закрытие файла void outputFile (const string& filename) { // open input file ifstream file(filename.c_str()); // Файл открыт? if (! file) { // НЕТ, аварийное завершение программы cerr << ToRus("Не могу открыть файл \"") << filename << "\"" << endl; exit(EXIT_FAILURE); } // Копирование содержимого файла в cout char c; while (file.get(c)) { cout.put(c); } } // Автоматическое закрытие файла //---------------------------------------------------------------------------
Результат работы приложения изображен на рисунке 1
Рис.1. Результат работы приложения
В функции writeCharsetToFile() конструктор класса ofstream открывает файл с заданным именем:
std::ofstream file(filename.c_str());
Имя файла передается в типе string, поэтому его преобразование в const char* выполняется функцией c_str(). К сожалению, у классов файловых потоков данных не существует конструктора, вызываемого с аргументом типа string. После преобразования программа проверяет состояние потока данных:
if (!file) {
. . . .
}
Если открыть поток данных не удалось, условие будет истинным. После проверки программа в цикле выводит числа от 32 до 255 вместе с соответствующими символами.
Внутри функции outputFile() файл открывается конструктором класса ifstream, после чего происходит посимвольная запись нового содержимого файла.
В конце обеих функций открытые файлы автоматически закрываются при выходе соответствующих потоков данных из области видимости. Деструкторы классов ifstream и ofstream закрывают файлы, если они остаются открытыми на момент уничтожения объекта.
Если файл должен использоваться за пределами области видимости, в которой он был создан, выделите объект из кучи и удалите его позднее, когда надобность в нем отпадет:
std::ofstream* filePtr = new std::ofstream("xyz"); . . . . . delete filePtr;
В таких случаях следует использовать классы умных указателей, например CountedPtr (смотри 190 шаг) или auto_ptr (смотри 59 шаг).
Вместо последовательного вывода отдельных символов также можно вывести все содержимое файла одной командой, передавая указатель на потоковый буфер файла в аргументе оператора <<:
std::cout << file.rdbuf();
На следующем шаге мы рассмотрим режимы открытия файлов.