Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lek13_14.doc
Скачиваний:
9
Добавлен:
13.07.2019
Размер:
695.3 Кб
Скачать

Файловый ввод-вывод

Во всех программах на языке C++, рассмотренных до сих пор, для ввода и вывода данных применялись стандартные потоки cin и cout. Если для этих же целей удобнее работать с файлами, следует воспользоваться классами ifstream и ofstream, которые порождены от классов istream и ostream и унаследовали от них функции, соответственно, чтения и записи. Необходимо также подключить файл FSTREAM (он, в свою очередь, включает файл IOSTREAM). В следующей программе демонстрируется работа с файлами посредством классов ifstream и ofstream:

// //   fstream. cpp //   Эта программа на языке C++ демонстрирует, как создавать //  потоки ifstream и ofstream для обмена данными с файлом. //

#include <fstream>

int main() {

char c;

ifstream ifsin("text.in",   ios::in);

if(lifsin)

cerr<<  "\nНевозможно открыть файл text.in для чтения.";

ofstream ofsout("text.out",   ios::out);

if(!ofsout)

cerr<<  "\nНевозможно открыть файл text.outдля записи.";

while (ofsout &&  ifsin.get(c)   )  ofsout.put (c);

ifsin.close ();  ofsout.close () ;

return(0); }

Программа создает объект ifsin класса ifstream и связывает с ним файл TEXT.IN, находящийся в текущем каталоге. Всегда следует проверять доступность указанного файла. В данном случае проверка осуществляется достаточно оригиналь­ным образом. Оператор ! в потоковых классах перегружен таким образом, что, будучи примененным к соответствующему объекту, при наличии каких-либо ошибок в потоке возвращает ненулевое значение. Аналогичным образом создается и объект ofsout класса ostream, связываемый с файлом TEXT.OUT.

В цикле while осуществляется считывание и запись отдельных символов в выходной файл до тех пор, пока в ряду символов не попадется EOF. При завершении программы закрываются оба файла. Особенно важно закрыть файл, в который записывались данные, чтобы предупредить потерю информации, еще находящейся в буфере.

Иногда возникают ситуации, когда необходимо отложить процесс спецификации файла или когда с одним объектом нужно последовательно связать сразу несколько потоков. В следующем фрагменте показано, как это сделать:

ifstream ifsin; . . . ifsin.open("weekl.in"); . . . if sin.close () ; ifsin.open("week2.in") . . . if sin. close () ;

Если необходимо изменить режим доступа к файлу, то это можно сделать путем модификации второго аргумента конструктора соответствующего файлового объекта, Например:

ofstream ofsout("file.out", ios::app | ios::nocreate);

В данном выражении делается попытка создать объект ofsout и связать его с файлом FILE.OUT. Поскольку указан флаг ios::nocreate, подключение не будет создано, если файл FILE.OUT не существует. Флаг ios::app означает, что все выводимые данные будут добавляться в конец файла. В следующей таблице перечислены флаги, которые можно использовать во втором аргументе конструкторов файловых потоков (допускается объединение флагов с помощью операции побито­вого ИЛИ):

Флаг Назначение

ios: : in                    Файл открывается для чтения, его содержимое не очищается

ios: : out                  Файл открывается для записи

ios: : ate                 После создания объекта маркер текущей позиции устанавливается в конец файла

ios: : арр                   Все выводимые данные добавляются в конец файла

ios: : trunc              Если файл существует, его содержимое очищается (автоматически устанавливается при открытии файла для записи)

ios: : nocreate      Объект не будет создан, если файл не существует

ios: : noreplace   Объект не будет создан, если файл существует

ios: : binary          Файл открывается в двоичном режиме (по умолчанию — в текстовом)

Для обмена данными с файлом можно также использовать объект класса fstream. Например, в следующем выражении файл UPDATE.DAT открывается для чтения и записи данных:

fstream io("update.dat",   ios::in   |   ios::app);

К объектам класса iostream(а класс fstream является его потомком) можно применять функции seekg() и seekp(),позволяющие управлять положением маркера текущей позиции файла. Функция seekg() задает положение маркера, связанного с чтением данных из файла, а функция seekp() — с записью. Обе функции требуют указания одного или двух аргументов. Если указан один аргумент, он считается абсолютным адресом маркера. Если два, то первый задает относительное смещение, а второй — направление перемещения. Существует также функция tellg(), возвращающая текущее положение маркера чтения, и функция tellp(), возвращающая текущее положение маркера записи. Рассмотрим небольшой фрагмент программы:

streampos current_position = io.tellp();

io << objl << obj2 << obj3;

io.seekp(current_position);

io.seekp(sizeof(objl), ios::cur);

io<< newobj2;

Сначала создается указатель current_position типа streampos, который инициализируется текущим адресом маркера записи. Во второй строке в поток io записываются три объекта. В третьей строке с помощью функции seekp() указатель перемещается в сохраненную позицию. Далее с помощью оператора sizeof() вычисляется объем памяти в байтах, занимаемый в файле объектом obj1, и функция seekp() "перескакивает" через него. В результате поверх объекта obj2 записывается объект newobj2.

Вторым аргументом функций seekg() и seekp() может быть один из следующих флагов: ios::beg(смещение на указанную величину от начала файла), ios::cur(смещение на указанную величину от текущей позиции) и ios::end (смещение на указанную величину от конца файла). Например, данное выражение переместит маркер чтения на 5 байтов от текущей позиции:

io.seekg(5,   ios::cur);

Следующее выражение переместит маркер на 7 байтов от конца файла:

io.seekg(-7,   ios::end);

Определение состояния потока

С каждым потоком связана внутренняя переменная состояния. В случае возник­новения ошибки устанавливаются определенные биты этой переменной в зависимо­сти от категории ошибки. Общепринято, что если поток класса ostream находится в ошибочном состоянии, то функции записи не выполняются и не меняют состояние потока. Существует ряд функций, позволяющих определить состояние потока:

Функция                       Действие

eof()                 Возвращает ненулевое значение при обнаружении конца файла

fail()                  Возвращает ненулевое значение в случае возникновения какой-либо ошибки в потоке, возможно не фатальной; если функция bad() при этом возвращает 0, то, скорее всего, можно продолжать работу с потоком, предварительно сбросив флаг ios:: failbit

bad()                 Возвращает ненулевое значение в случае возникновения серьезной ошибки ввода-вывода; в этом случае продолжать работу с потоком не рекомендуется

good()               Возвращает ненулевое значение, если биты состояния не установлены

rdstate()             Возвращает текущее состояние потока в виде одной из констант: ios::goodbit(нет ошибки), ios:: eofbit(достигнут конец файла), ios::failbit(возможно, некритическая ошибка форматирования или преобразования), ios: :badbit(критическая ошибка)

clear()                Задает состояние потока; принимает аргумент типа int, который по умолчанию равен 0, что соответствует сбросу всех битов состояния, в противном случае содержит одну или несколько перечисленных в предыдущем пункте констант, объединенных с помощью операции побитового ИЛИ (|)

Приведем пример:

ifstream pfsinfile("sample.dat", ios::in);

if (pfsinfile.eof ())

pfsinfile.clear() ;   //  состояние потока pfsinfile сбрасывается

if (pfsinfile. fail () )

cerr<< ">>> ошибка при создании файла sample.dat<<<";

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Классы ввода-вывода в языке C++

В лекции "Основы ввода-вывода в языке C++" были даны общие представления о потоковых объектах cin, cout и cerr и операторах потокового ввода-вывода << и >>. Сейчас мы поговорим о стандартных классах C++, управляющих работой этих объектов.

Иерархия классов ввода-вывода

Все потоковые классы порождены от одного класса, являющегося базовым в иерархии, — ios. Исключение составляют лишь классы буферизованных потоков, базовым для которых служит класс streambuf. Всех их можно разделить на четыре категории, как показано в табл. 6.

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

Классы семейства ios предоставляют программный интерфейс и обеспечивают необходимое форматирование обрабатываемых данных, тогда как непосредственную обработку данных выполняют классы семейства streambuf, управляющие обменом данными между буфером потока и конечным устройством (рис. 4).

Таблица 6. Категории классов ввода-вывода

Класс

Описание

ios        

Содержит базовые средства управления потоками, является родительским для других классов ввода-вывода (файл IOSTREAM)

Потоковый ввод

istream 

Содержит общие средства потокового ввода, является родительским для других классов ввода (файл IOSTREAM)

ifstream

 Предназначен для ввода данных из файлов (файл FSTREAM)

istream_withassign   

Поддерживает операцию присваивания; существует предопределенный объект cin данного класса, по умолчание читающий данные из стандартного входного потока, но благодаря операции присваивания этот объект может быть переадресован на различные объекты класса istream(файл IOSTREAM)

istrstream

Предназначен для ввода данных из строковых буферов (файл STRSTREA)

Потоковый вывод

ostream

 Содержит общие средства потокового вывода, является родительским для других классов вывода (файл IOSTREAM)

ofstream

Предназначен для вывода данных в файлы (файл FSTREAM)

ostream_withassign 

Поддерживает операцию присваивания; существуют предопределенные объекты cout, cerr и clog данного класса, по умолчанию выводящие данные в стандартный выходной поток, но благодаря операции присваивания их можно переадресовать на различные объекты класса ostream (файл IOSTREAM)

ostrstream 

Предназначен для вывода данных в строковые буферы (файл STRSTREA)

Потоковый ввод-вывод

iostream 

Содержит общие средства потокового ввода-вывода, является родительским для других классов ввода-вывода (файл IOSTREAM)

fstream  

Предназначен для организации файлового ввода-вывода (файл FSTREAM)

strstream

Предназначен для ввода-вывода строк (файл STBLSTREA)

stdiostream

Поддерживает работу с системными средствами стандартного ввода-вывода, существует для совместимости со старыми функциями ввода-вывода (файл STDIOSTR)

Буферизованные потоки

streambuf

Содержит общие средства управления буферами потоков, является родительским для других буферных классов (файл IOSTREAM)

filebuf

Предназначен для управления буферами дисковых файлов (файл FSTREAM)

strstreambuf

 Предназначен для управления строковыми буферами, хранящимися в памяти (файл STRSTREA)

stdiobuf 

Осуществляет буферизацию дискового ввода-вывода с помощью стандартных системных функций (файл STDIOSTR)

Рис. 3. Иерархия классов ввода-вывода порожденных от ios Рис. 4. Иерархия классов, порожденных от streambuf

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]