- •Ввод-вывод в языке с
- •Потоковые функции
- •Открытие файлов и потоков
- •Переадресация ввода-вывода
- •Изменение буфера потока
- •Форматный вывод данных
- •Функция printf()
- •Поиск в файлах с помощью функций fseek( ), ftell( ) и rewind()
- •Синхронный и асинхронный ввод/вывод
- •3. Позиционирование указателя файла.
- •6. Запись данных в файл
- •Блокировка и разблокировка файла
- •Асинхронный режим чтения и записи файлов
- •Стандартные потоки cin, coutи cerr
- •Флаги и функции форматирования
- •Файловый ввод-вывод
- •Флаг Назначение
- •Файловый ввод
- •Файловый вывод
- •Вот результаты работы программы:
- •Двоичные файлы
- •Буферы потоков
Файловый ввод-вывод
Во всех программах на языке 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