- •Лабораторна робота №11 (2 год.) Робота з файлами. Файлові потоки.
- •Теоретичні відомості
- •2. Потоки як узагальнені фільтри
- •Приклад 1. Простий приклад потокового вводу-виводу
- •3. Введення-виведення типів char I char*
- •4. Введення-виведення типів int I long
- •5. Введення-виведення типів float I double
- •6. Введення-виведення класів користувача
- •Приклад 3. Ввід-вивід класу користувача
- •7. Маніпулятори
- •8. Використання текстових файлів для введення
- •Приклад 4. Читання і перевірка файлу на помилки
- •9.Виведення текстових файлів
- •10. Читання бінарних файлів
- •Приклад 6. Читання текстового файлу в бінарному режимі
- •11. Запис у бінарні файли
- •12. Копіювання файлів
- •1. Потоки і потік введення - виведення
- •2. Текстові і двійкові потоки
- •3. Буферизація потоків
- •4. Стандартні потоки
- •5. Приклад програми роботи з файлами
- •6. Різниця при роботі з файлами у мовах Паскаль та с
- •Завдання
Лабораторна робота №11 (2 год.) Робота з файлами. Файлові потоки.
Мета роботи: Вивчити принципи організації введення-виведення даних та роботи з файлами даних в C++.
Теоретичні відомості
Введення-виведення даних у С++, а також робота з файлами здійснюється з використанням потоків.
ІІ. Засоби мови С для роботи з потоками
1. Потоки С++
С++ була розроблена для класів, але сама рідко їх використовує, а якщо і використовує, то через бібліотеки. Потоки С++ як раз і виділяються тим, що реалізовані виключно через класи. Зараз використовується бібліотека класів iostream (iostream library), вперше представлена в АТ&Т С++ версії 2.0.
Потоки реалізовано окремо від функцій stdio. Тому при використанні в програмі одночасно і потоків, і stdio можуть виникнути проблеми. Якщо один символ виводиться потоковою операцією, а інший – функцією stdio putc(…), то порядок появи символів може бути порушеним через внутрішню буферизацію і автоматичне очищення буфера.
2. Потоки як узагальнені фільтри
Потоки складають захисну оболонку, яка надає операціям вводу-виводу поліморфні і об’єктно-орієнтовані властивості. Незважаючи на те, що потоки часто асоціюються саме з вводом-виводом, реально вони є абстракцією передачі даних від одного об”єкта до іншого за допомогою механізму буферизації. Це означає, що бідь-яка функція, що використовується для передачі даних з одного місця в пам’яті в інше (зі зміною даних або без), може розглядатися як потокова операція. Наприклад, старі функції ANSI С memmove(...), sprintf(...), strcpy(...) можна реалізувати як потокові операції, оскільки вони представляють собою передачу даних в пам’яті: дані переходять так, як би це був потік.
В бібліотеці потоків є багато класів, які можна розділити на три категорії (табл. 1). Там же приведено список тих стаих функцій ANSI, які вони заміняють.
Таблиця 1. Нові категорії потоку і приклади функцій ANSI, які вони замінюють.
Категорія потоку |
Приклади функцій ANSI, які їх замінюють |
Стандартний ввід-вивід |
scanf(...), printf(...) |
Ввід-вивід файлів |
fopen(...), fread(...), fclose(...) |
Форматування в пам’яті |
Sscanf(...),sprintf(...) |
Стандартний потоковий ввід-вивід з вбудованими типами даних
Потоки вносять у ввід-вивід багато елегантних можливостей перевантаження операторів і об’єктної орієнтованості. Мета потоків – надати уніфікований запис для різних типів даних, що вводяться і виводяться, переклавши всі деталі на компілятор. Потокові оператори записуються наступним чином:
потік_вводу >> типізована_зміна;
потік_виводу << типізована_зміна;
Об’єкт потоку завжди міститься в лівій частині виразу. Оператори >> і << вказують на напрям потоку даних від одного об’єкта до іншого. З потоком вводу-виводу можна використовувати будь-який вбудований тип даних. Класи користувача, якщо вони були розроблені для підтримки вводу-виводу, також сумісні з потоком. Всі випадки в прикладі 1 допустимі.
Приклад 1. Простий приклад потокового вводу-виводу
#include <iostream.h>
void main()
{
int a;
char c;
float f;
double d;
cin >> a;
cin >> c;
cin >> f;
cin >> d;
cout << a;
cout << c;
cout << f;
cout << d;
cout << “\nThis is a short string”;
cout << “\nAnd this is a three”
<< “\nline message that”
<< “\nis a little longer”;
}
С++ підтримує визначення стандартних шляхів вводу і виводу даних, але замість файлів використовуються потоки. Потік cin – стандартний символьний потік вводу, зазвичай пов’язаний з клавіатурою. Він замінює stdin, який використовувався з тією ж метою в ANSI C. Потік cout подібний до stdout і зазвичай пов’язанй з таким символьним вивідним пристроєм, як дисплей персонального комп’ютера. Крім цього, в Borland C++ визначені і інші стандартні потоки: cerr (замінює stderr як стандартний потік виводу) і clog (аналога якому в ANSI C не було). Потік clog подібний до cerr, але забезпечує буферизацію, тоді як cin, cout і cerr її не забезпечують. Кожен з цих чотирьох потоків розглядається окремо.
Чотири стандартних потоки cin, cout, cerr і clog автоматично відкриваються до початку виконання функції main() і закриваються після її завершення. Так що не слід турбуватися про оголошення, відкриття і закриття потоків. А ось очищення потоків в залежності від вимог програми слід включити (#include) стандартний заголовочний файл iostream.h. Об’єкт потоку повинен стояти в лівій частині операторів << або >>. Кілька потокових операцій, навіть тоді, коли вони відносяться до об’єктів різних типів, можуть бути об’єднані в одну стрічку. Комбінація символів >> називається оператором вилучення, оскільки вони використовуються для отримання символів з потоку. Символи << називаються оператором вставки, оскільки використовуються для поміщення символів в потік. Приклад 1 можна переписати наступним чином:
void main()
{
int a;
char c;
float f;
double d;
cin >> a >> c >> f >> d; //ввід всіх даних
cout << a << c << f << d; //вивід всіх даних
Компілятор відслідковує перетворення типів і форматування даних. З першого оператора компілятор генерує чотири окремих операції вводу (по одній для кожної змінної). Оператор >> – ліво-асоціативний, тому змінна a читається перед змінною c. З другого оператора отримуємо чотири операції виводу. Оператор <<, як і оператор >>, ліво-асоціативний, тому a виводиться перед c. Форматування здійснюється автоматично самим потоком, що знижує рівень необхідних подробиць до мінімального. Керувати форматуванням можна за допомогою спеціальних функцій-маніпуляторів.
Введення у ANSI C, на відміну від С++, вимагало від програміста передавати кілька аргументів, що збільшувало імовірність помилок. Підводним каменем в С, об який спотикалися дуже багато програмістів, було використання старих функцій scanf(...) і printf(...) для того, щоб зробити щось, подібне до наступного:
int i;
float f;
scanf(“%d”, i); /*передача параметра по значенню*/
printf(“%d”, f); /*неправильний форматуючий символ*/
замість правильного запису:
int i;
float f;
scanf(“%d”, &i); /*це правильно*/
printf(“%f”, f); /*і це вірно*/