- •Объектно-ориентированное программирование:
- •Содержание
- •Новый тип данных – класс
- •1.2. Доступность компонентов класса
- •1.3. Конструктор и деструктор
- •1.4.4. Статические члены класса
- •1.4. Компоненты-данные и компоненты-функции
- •1.4.1. Данные – члены класса
- •1.4.2. Функции – члены класса
- •1.4.3. Константные компоненты-функции
- •Указатели на компоненты класса
- •1.5.1. Указатели на компоненты-данные
- •1.5.2.Указатели на компоненты-функции
- •1.6. Указатель this
- •1.7. Друзья классов
- •7.1. Дружественная функция
- •1.7.2. Дружественный класс
- •1.8. Определение классов и методов классов
- •2. Наследование
- •2.1. Определение производного класса
- •2.2. Конструкторы и деструкторы производных классов
- •2.3. Виртуальные функции
- •2.4. Абстрактные классы
- •2.5. Включение объектов
- •2.6. Включение и наследование
- •2.7. Множественное наследование
- •2.8. Локальные и вложенные классы
- •2.9. Пример программы для Microsoft Visual Studio
- •2.10. Упражнения
- •3. Перегрузка операций
- •3.1. Перегрузка унарных операций
- •3.2. Перегрузка бинарных операций
- •3.4. Перегрузка операции вызова функции
- •3.5. Перегрузка операции присваивания
- •3.6. Перегрузка операции new
- •3.7. Перегрузка операции delete.
- •3.8. Основные правила перегрузки операций
- •3.9. Примеры программ
- •4. Шаблоны функций и классов
- •4.1. Шаблоны функций
- •4.2. Шаблоны классов
- •4.3. Компонентные функции параметризованных классов
- •4.4. Примеры программ.
- •5. Обработка исключительных ситуаций
- •5.2. Получение дополнительной информации об исключении
- •5.3. Определение типа исключения
- •5.4. Иерархия исключений
- •5.5. Спецификация функций, обрабатывающих исключения
- •6. Потоковые классы
- •6.1. Библиотека потоковых классов
- •6.3. Стандартные потоки ввода-вывода
- •6.4. Форматирование
- •6.5. Манипуляторы
- •6.6. Ввод-вывод объектов пользовательских классов
- •6.7. Определение пользовательских манипуляторов
- •6.8. Пользовательские манипуляторы с параметрами
- •6.9. Использование макросов для создания манипуляторов
- •6.10. Состояние потока
- •6.11. Неформатированный ввод-вывод
- •6.12. Файловый ввод-вывод
- •7.1. Пространство имен
- •7.2. Динамическая идентификация типов
- •7.3. Безопасное приведение типа
- •8. Стандартная библиотека шаблонов
- •8.1. Введение в stl
- •Парадигму обобщенного программирования можно сформулировать следующим образом:
- •8.2. Итераторы
- •8.3. Классы-контейнеры
- •Iterator find(const key_type&k)
- •Iterator lower_bound(const key_type&k)
- •Iterator upper_bound(const key_type&k)
- •8.4. Контейнер vector
- •8.5. Многомерные массивы
- •8.6. Ассоциативные контейнеры
- •8.7. Объекты-функции
- •8.8. Алгоритмы
- •I. Немодифицирующие операции
- •II. Модифицирующие операции
- •III. Сортировка
- •IV. Работа с множествами
- •V. Минимумы и максимумы
- •VI. Перестановки
6.12. Файловый ввод-вывод
Потоки для работы с файлами создаются как объекты следующих классов:
ofstream – запись в файл;
ifstream – чтение из файла;
fstream – чтение/запись.
Для создания потоков имеются следующие конструкторы:
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. Новые возможности языка С++
