Тема 8. Файлові потоки вводу-виводу в С++
Зміст теми. Файлові потоки. Створення файлів. Читання даних з файлів. Запис даних у файл. Відкриття та закриття файлів. Режими відкриття файлу.
У С++ кожен файл розглядається як послідовний потік байтів. За способом доступу файли можна розділити на послідовні, читання і запис в яких проводиться з початку байт за байтом, і файли з довільним доступом, що допускають читання і запис у вказану позицію. Файл завершується маркером кінця файлу (EOF – end-of-file marker).
Стандартна бібліотека містить три класи для роботи з файлами:
ifstream – клас вхідних файлових потоків;
ofstream – клас вихідних файлових потоків;
fstream – клас двонаправлених файлових потоків.
Використання файлів в програмі припускає наступні операції: створення потоку, відкриття потоку і скріплення його з файлом, обмін (введення/виведення), знищення потоку, закриття файлу.
Для використання файлів у С++ повинно включити заголовний файл <fstream>. Файл <fstream> включає визначення класів для створення файлових потоків: ifstream (для читання з файлу), ofstream (для запису у файл) і fstream (для читання і запису у файл). Ці класи потоків є похідними (тобто успадковують функціональні можливості) відповідно від класів ostream,. iostream, istream. Таким чином, функции, операції (<< і >>) і маніпулятори можуть бути також застосовані і до потоків файлів.
Кожен клас файлових потоків містить конструктори, за допомогою яких можна створювати об'єкти цих класів різними способами. Конструктори без параметрів створюють об'єкт відповідного класу, не пов'язуючи його з файлом:
ifstream();
ofstream();
fstream().
Конструктори з параметрами створюють об'єкт відповідного класу, відкривають файл з вказаним ім'ям (*name) і пов'язують файл з вказаним об'єктом:
ifstream(const char *name, int mode = ios::in);
ofstream(const char *name, int mode = ios::out | ios::trunc);
fstream(const char *name, int mode = ios::in | ios::out).
Другим параметром конструктора є режим відкриття файлу. Якщо встановлене за замовчанням значення не влаштовує програміста, можна вказати інше.
Відкрити файл в програмі можна з використанням або конструкторів, або методу open(), що має такі ж параметри, як і у відповідному конструкторі.
Для закриття потоку визначений метод close(), але оскільки він неявно виконується деструктором, явний виклик необхідний тільки тоді, коли потрібно закрити потік раніше кінця його області видимості.
Таблиця– Режими відкриття файлів
Режим |
Опис |
ios::app |
Відкрити файл для додавання даних у кінець файлу |
ios::ate |
Перемістити покажчик в кінець файлу. |
ios::in |
Відкрити файл для читання (вводу). |
ios::out |
Відкрити файл для запису (виводу) |
ios::trunc |
Якщо файл існує, видалити (це також за замовчуванням робиться для ios::out). |
ios::nocreate |
Якщо файл не існує, то видати помилку. |
ios::noreplace |
Якщо файл існує, то видати помилку. |
ios::binary |
Відкрити файл у двійковому режимі |
Приклади відкриття файлу Tovar.dat для запису:
1) ofstream f(("Tovar.dat"); // оголошення файлового потоку виводу й відкриття файлу Tovar.dat для запису
2) ofstream f; // оголошення файлового потоку виводу
f.open ("Tovar.dat"); // відкриття файлу Tovar.dat
3) fstream f ("Tovar.dat", ios::out); // оголошення файлового потоку вводу/виводу й відкриття для запису
4) fstream f; // оголошення файлового потоку вводу/виводу
f.open ("Tovar.dat", ios::out); // відкриття файлу для запису
5) fstream f ("Tovar.dat", ios::app); // оголошення файлового потоку вводу/виводу й відкриття файлу Tovar.dat для додавання
Приклади відкриття файлу Tovar.dat для читання:
1) ifstream f(("Tovar.dat"); // оголошення файлового потоку вводу й відкриття файлу Tovar.dat для читання
2) ifstream f; // оголошення файлового потоку вводу
f.open ("Tovar.dat"); // відкриття файлу Tovar.dat
3) fstream f ("Tovar.dat", ios::in); // оголошення файлового потоку вводу/виводу й відкриття для читання
4) fstream f; // оголошення файлового потоку вводу/виводу
f.open ("Tovar.dat", ios::in); // відкриття файлу для читання
Після створення об'єкта будь-якого класу файлових потоків і спроби відкрити його, програма може перевірити, чи була операція відкриття файлу успішною. Наприклад:
if (!f)
{
cerr «"Файл не може бути відкритий" << endl; exit (1) ;
}
Деякі можливі помилки є слідством спроби відкрити для читання неіснуючий файл, спроби відкриття файлу для запису, коли на диску немає вільного місця і т.д. Коли умова вказує, що спроба відкриття файлу була безуспішною, виводиться повідомлення «Файл не може бути відкритий» і викликається функція exit для завершення програми. Аргумент функції exit повертається середовищу оточення, з якого програма була викликана. Аргумент 0 показує, що програма завершується нормально, а будь-яке інше значення, указує середовищу оточення, що програма припинила виконання із-за помилки. Значення, що повертає функція exit, використовується середовищем оточення (найчастіше операційною системою) для відповідної реакції на помилку.
Приклад запису у файл із використанням функції write
CTovar Tovar; //оголошення об'єкта
ofstream fTovOut ("Tovar.dat", ios::app); // оголошення файлового потоку виводу fTovar і відкриття файлу для додавання
Tovar.input(); //виклик функції input() об'єкта Tovar
fTovOut.write((char*)&Tovar,sizeof(Tovar)); // запис у файл даних об'єкта Tovar
fTovOut.close(); // закриття файлу
Приклад запису у файл із використанням операції << (помістити в потік):
void CTovar::input()
{
ofstream fTovOut ("Tovar.dat", ios::app);
cout <<"Уведіть найменування товару ";
cin >>name;
cout <<"Уведіть ціну товару ";
cin >>price;
fTovOut <<name <<' '<< price<<endl; // запис у файл Tovar.dat
fTovOut.close();
}
Для читання з файлу можна використовувати функцію read() класу ifstream і операцію >> (узяти з потоку).
Приклад читання з файлу всіх даних з використанням функції read():
ifstream fTovIn("Tovar.dat"); // оголошення файлового потоку уведення fTovar і відкриття файлу для читання
fTovIn.read ((char*)&Tovar,sizeof(Tovar)); // читання з файлу даних в об'єкт Tovar
while (fTovIn.Eof()) // поки не кінець файлу
{
Tovar.output();
fTovIn.read ((char*)&Tovar,sizeof(Tovar));
}
Приклад читання з файлу всіх даних з використанням операції >> (узяти з потоку) і вивід їх на екран:
void CTovar::output()
{
ifstream fTovIn("Tovar.dat");
cout <<"Найменування товару "<<" Ціна товару "<<endl ;
while (fTovIn>>name>>price) //поки є дані читати з файлу
{
cout<<" "<<setiosflags(ios::left)<<setw(15) << name
<<setprecision(2) <<setiosflags(ios::right)<<setw(10)<<price<<"\n"; }
}
Запитання для самоконтролю