Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ООП на языке С++.docx
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
2 Мб
Скачать
☆

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

Потоки для работы с файлами создаются как объекты следующих классов:

ofstream – запись в файл;

ifstream – чтение из файла;

fstream – чтение/запись.

Для создания потоков имеются следующие конструкторы:

  1. fstream();

создает поток, не присоединяя его ни к какому файлу.

2) fstream(int file_descriptor);

создает поток и присоединяет его к уже открытому файлу.

3)fstream(int fd,char* buffer,int size);

Этот конструктор получает буфер buffer размером size и использует его для создания внутреннего объекта filebuf. Поток присоединяется к уже открытому файлу.

4)fstream(const char* name,int mode,int p=filebuf::openprot);

создает поток, присоединяет его к файлу с именем name, предварительно открыв файл, устанавливает для него режим mode и уровень защиты p. Если файл не существует, то он создается. Для m=ios::out, если файл существует, то его размер будет усечен до нуля. Флаги режима имеют следующие значения.

enum ios::open_mode{

in=0X01, //для чтения

out=0X02, //для записи

ate=0X04, /*индекс потока помещен в конец файла. Чтение больше не допустимо, //выводные данные записываются в конец файла. При открытии файла //ищется конец файла. Далее можно указать seekp(k);*/

app=0X08, /*поток открыт для добавления данных в конец. Независимо от seekp будет писаться в конец */

trunc=0X10, //усечение существующего потока до нуля

nocreate=0X20, /*команда открытия потока будет завершена неудачно, если файл не существует*/

noreplace=0X40, /*команда открытия потока будет завершена неудачно, если файл существует*/

binary=0X80, //поток открывается для двоичного обмена

};

static const int filebuf::openprot указывает на тип защиты доступа к файлам. Система DOS предлагает ограниченный набор защитных механизмов, поэтому по умолчанию защита файлов установлена в(S_IREAD|S_IWRITE). Системы UNIX могут использовать openprot для предоставления определенным категориям пользователей прав на чтение, запись или выполнение файла.

Если при создании потока он не присоединен к файлу, то присоединить существующий поток к файлу можно функцией.

void open(const char* name,int mode,int p=filebuf::openprot);

Функция void fstreambase::close(); сбрасывает буфер потока, отсоединяет поток от файла и закрывает файл. Эту функцию необходимо явно вызвать при изменении режима работы с потоком. Автоматически она вызывается только при завершении программы.

Пример 6.12.1. Запись в бинарные файлы

#include<iostream.h>

#include<fstream.h>

struct Person{

char name[10];

int age;

float salary;};

void main

{//открытие файла

ofstream fout(“person.dat”,ios::binary);

//проверка на ошибки открытия

if(!fout){cout<<“Ошибка\n”; return;}

Person employee;

int k=0;

while(k<10 && fout)

{cout<<“name=”;

cin>> employee.name;

cout<<“age=”;

cin>> employee.age;

cout<<“salary=”;

cin>> employee.salary;

fout.write((char*)&employee,sizeof(employee));

k++;}

fout.seekp(0,ios::end);

long size=fout.tellp();

cout<<“записано ”<<size<<“ байт\n”;

}

Пример 6.12.2. Чтение бинарного файла

#include<iostream.h>

#include<fstream.h>

struct Person;

void main()

{ifstream fin(“person.dat”,ios::binary);

if(!fin){cout<<“Ошибка\n”; return;}

fin.seekg(0,ios::end);

long size=fin.tellg();

cout<<“В файле ”<<size<<“ байт\n”;

fin.seekg(0,ios::beg);

Person employee;

int k=0;

fin.read((char*)&employee,sizeof(employee));

while(fin)

{cout<<“name=”<<employee.name<<“ age=”<<employee.age

<<“ salary=”<<employee.salary<<endl;

k++;

fin.read((char*)&employee,sizeof(employee));}

cout<<“прочитано ”<<k<<“ записей\n”;

}

Пример 6.12.3. Запись в бинарный файл структуры перегруженной операцией <<

#include<fstream.h>

struct Person;

ofstream& operator<<(ofstream& out, Person& item)

{out.write((char*)& item,sizeof(item));}

void main()

{ofstream fout(“person.dat”,ios::binary);

if(!fout){…}

int k=0;

TPerson employee;

while(k<10 && fout)

{//сформировать employee

fout<<employee;

k++;}

fout.seekp(0,ios::end);

long size=fout.tellp();

cout<<“записано ”<<size<<“ байт\n”;

}

Общая схема записи в файл

1)создать потоковый объект

fstream f;

2)открыть для записи

f.open(“имя”,ios::out|ios::binary);

3)выполнять в цикле запись из переменной в файл

f.write((char*)&zap,sizeof(zap));

4)закрыть файл

f.close();

Общая схема чтения из файла

1)создать потоковый объект

fstream f;

2)открыть для чтения

f.open(“имя”,ios::in|ios::binary);

3)выполнить в цикле чтение из файла в переменную

f.read((char*)&zap,sizeof(zap));

Открыть файл для изменений (чтения/записи) следует следующим образом:

f.open(“имя”,ios::binary|ios::in|ios::out);

Если указать режим только out без in, то файл усекается до нуля.

Если требуется только писать в файл (в любую позицию), то следует открыть его следующим образом

f.open(“имя”,ios::binary|ios::out|ios::ate);

Если указать только ate без out, то файл не откроется. Если вместо ate указать app, то данные будут писаться всегда в конец файла независимо от seekp().

Таким образом, открытие файла на запись в режиме ios::out приведет к усечению существующего файла до нуля. Для того, чтобы это предотвратить, нужно использовать режим ios::ate. При этом после открытия индекс файла переместится в конец. Затем, если необходимо, перемещение по файлу осуществляет seekp(). Если при открытии был использован режим ios::app, то все данные будут записываться в конец файла, независимо от того, какие команды seekp() выдавались. Однако команда seekg() все же влияет на операцию чтения.

Команда открытия файла выполняется успешно, независимо от того, существует файл или нет. Чтобы предотвратить открытие уже существующего файла, нужно воспользоваться режимом открытия ios::noreplace. Чтобы возникла ошибка, когда файла нет, нужно воспользоваться режимом ios::nocreate.

Как проверить файловый поток на ошибки?

Пусть имеется следующий поток fstream stream. Тогда

if(!stream) //ошибка была

if(stream) //ошибки не было

Более подробную информацию об ошибке можно получить с помощью следующих функций:

if(stream.bad()) //были ошибки

if(stream.eof()) //конец файла

if(stream.good()) //ошибок не было

Если произошла ошибка потока, то дальнейшая работа с ним блокируется. Для продолжения работы необходимо очистить все биты ошибок потока, выполнив функцию clear(), например stream.clear();

Если установлен бит ошибки при чтении за концом файла, то для продолжения работы с файлом следует сбросить бит ios::eofbit и переместить указатель get в начало файла.

stream.clear();stream.seekg(0);

Если требуется проверить, открыт ли файл, то следует использовать функцию is_open(), которая возвращает true, если файл открыт, например,

if(!stream.is_open()) //файл не открыт

В заключении перечислим возможные способы открытия файла для операций ввода/вывода.

1.

Создается объект filebuf

filebuf fbuf;

Объект filebuf связывается с устройством файлом, который открывается в требуемом режиме

fbuf.open(“имя”,ios::in);

Создается поток и связывается с filebuf

istream stream(&fbuf);

2.

Создается поток fstream (ifstream, ofstream)

fstream stream;

Открывается файл, который связывается через filebuf с потоком

stream.open(“имя”,ios::in);

3.

Создается объект fstream, одновременно открывается файл, который связывается с потоком

fstream stream(“имя”,ios::in);

4.

Файл открывается функцией ANSI C

FILE* f;

f=fopen(“имя”,”r”);

Создается поток fstream (ifstream, ofstream) и связывается с файлом

fstream stream(*f.fd);

7. Новые возможности языка С++