Лекція 10. Потоки в С++. Робота з файлами з використанням потоків
Поняття потоку і потокового класу
Потік – це абстрактне поняття, яке стосується перенесення даних від джерела до приймача, від одного об’єкту до іншого за допомогою буферизації.
Потоки в С++, на відміну від функцій вводу/виводу в С, забезпечують:
Надійну роботу як із стандартиними, так і з користувацькими типами даних (класами).
Єдиновидний синтаксис.
Потік – це послідовність байт інформації, що передається або приймається, і не залежить від конкретного пристрою (оперативна пам’ять (ОП), екран, клавіатуру, принтер, файл на диску...). Для збільшення швидкості передачі даних викоритсовується буфер (buffer) – (для тимчасового зберігання даних).
За напрямом обміну потоки поділяються на: 1) вхідні (input) – дані вводяться в ОП; 2) вихідні (output) – дані виводяться з ОП; 3) двонапрямлені (input-output).
За видом пристроїв, з якими ведеться обмін, потоки поділяються на: 1) стандартні – (клавіатура, екран); 2) файлові – для обміну інформацією з файлами на зовнішніх носіях; 3) рядкові – для роботи з масивами символів (стрічками) в ОП.
Для підтримки потоків бібліотека С++ містить ієрархію класів, побудованих на базі двох основних класів – ios та streambuf.
Input – введення; output – виведення; stream - потік
Опис відповідних класів зроблено у файлах заголовків:
< iostream.h >, < fstream.h >, < strstream.h >
< iomanip.h > - маніпулятори
Стандартні потоки
< iostream.h > :
cin – забезпечує стандартну буферизацію введення даних з клавіатури (за замовч.).
cout – забезпечує стандартну буферизацію виведення даних на екран (за замовчув.).
cerr – використовується для виведення повідомлення про помилки. Повідомлення з’являється на екрані відразу після занесення в буфер.
clog – виводить повідомлення про помилки після заповнення всього буфера.
В класах istream, ostream операції занесення в потік << та вилучення >> позначені шляхом перевантаження операції зсуву:
friend ostream & operator << (ostream &, type)
{….
return ostream; }
friend istream & operator >> (istream &, type &)
Ці перевантажені операції формують посилання на об’єкт типу ostream або istream, що дозволяє робити їх зчіплення, тобто записувати багатократні операції занесення в потік або вилучення з потоку.
c out << a << b
Операції << та >> перевантажені до всіх стандартних типів. При введені рядків вилучення символів з потоку здійснюється до найближчого пропуску:
c har s1[100], s2[100]; cin >> s1 >> s2;
один два (три – не буде введено)
Якщо потрібно вводити з пропуском, то використовують get, getline.
3.Форматування даних.
В потокових класах форматування даних виконується трьома способами:
1) за допомогою прапорців;
2) за допомогою маніпуляторів;
3) за допомогою форматуючих методів.
Прапорці і форматуючі методи
Прапорцями є окремі біти, об'єднані в полі x_flags типу long класу ios. Прапорці перераховані в таблиці 1.
Таблиця 1. Прапорці форматування класу ios
Прапорець |
Поло- ження |
За замовчуванням |
Опис дії при встановленому прапорцеві |
skipws |
0x0001 |
+ |
При вилученні з потоку символи пропусків ігноруються |
left |
0x0002 |
|
Вирівнювання по лівому краю поля |
right |
0x0004 |
+ |
Вирівнювання по правому краю поля |
internal |
0x0008 |
|
Знак числа виводиться по лівому краю, число — по правому. Проміжок заповнюється символами x_fill, за замовчуванням пропусками |
dec |
0x0010 |
+ |
Десяткова система числення |
oct |
0x0020 |
|
Вісімкова система числення |
hex |
0x0040 |
|
Шістнадцяткова система числення |
showbase |
0x0080 |
|
Виводиться основа системи числення (0х для шістнадцяткових чисел і 0 для вісімкових) |
showpoint |
0x0100 |
|
При виведенні дійсних чисел друкувати десяткову крапку |
uppercase |
0x0200 |
|
При виведенні використовувати символи верхнього регістру |
showpos |
0x0400 |
|
Друкувати знак при виведенні додатніх чисел |
scientific |
0x0800 |
|
Друкувати дійсні числа у формі з плаваючою крапкою |
fixed |
0x1000 |
|
Друкувати дійсні числа у формі з фіксованою крапкою (точність визначається полем х_precision) |
unitbuf |
0x2000 |
|
Вивантажувати буфери всіх потоків після вставки |
stdio |
0x4000 |
|
Вивантажувати буфери потоків stdout і stderr після вставки |
Прапорці (left, right та internal), (dec, oct та hex), а також (scientific та fixed) взаємно виключають один одного, тобто в кожен момент може бути встановлений лише один прапорців з кожної групи.
Для управління прапорцями в класі ios є методи flags, setf і unsetf:
long ios :: flags(); — повертає поточні прапорці потоку;
long ios :: flags(long); — присвоює прапорцям значення параметра;
long ios :: setf (long, long); — присвоює прапорцям, біти яких встановлені у першому параметрі, значення відповідних бітів другого параметра;
long ios :: setf (long); — встановлює прапорці, біти яких встановлені у параметрі;
long ios :: unsetf (long); — скидає прапорці, біти яких зазаначені в параметрі.
Всі функції повертають попередні прапорці потоку.
Окрім прапорців, для форматування використовуються наступні поля класу ios:
int x_width — мінімальна ширина поля виведення;
int x_precision — точність (кількість цифр в дробовій при виведенні дійсних чисел);
int x_fill — символ заповнення поля виведення.
Для управління цими полями використовуються методи width, precision та fill:
int ios :: width() — повертає значення ширини поля ;
int ios:: width (int) — встановлює ширину поля відповідно до значення параметра;
int ios :: precision() — повертає значення точності подання при виведенні дійсних чисел;
int ios :: precision(int) — встановлює значення точності подання при виведенні дійсних чисел, повертає старе значення точності;
char fill () — повертає поточний символ заповнення;
char fill (char) — встановлює значення поточного символу заповнення, повертає старе значення символу.
Приклад форматування даних за допомогою прапорців і методів.
#include <iostream.h>
int main() {
long a = 1000, b = 077;
cout.width (7);
cout.setf (ios::hex | ios::showbase | ios::uppercase);
cout << a;
cout.width (7);
cout << b << endl;
double d = 0.12, c= 1.3e-4;
cout.setf (ios :: left);
cout << d << endl;
cout << c;
return 0; }
В результаті роботи програми в першому рядку будуть ВЕЛИКИМИ буквами виведені змінні а і b в шістнадцятковому поданні, для кожної з них виділяється по 7 позицій (функція width діє тільки на одне значення, що виводиться, тому її виклик потрібно повторити двічі). Значення змінних с і d прив’язані до лівого краю поля:
..ОХ3ЕВ ...0X3F
0.12
0.00013
Маніпулятори
Маніпуляторами називаються функції, які можна включати в ланцюжок операцій поміщення і добування для форматування даних. Маніпулятори поділяються на прості, які не вимагають вказівки аргументів, і такі,що параметризуються.
Користуватися маніпуляторами зручніше, ніж методами установки прапорців форматування.
Прості маніпулятори
Нижче перераховані маніпулятори, що не вимагають вказівки аргументів:
dec — встановлює при введенні/виведенні прапорець 10-ої системи числення;
oct — встановлює при введенні/виведенні прапорець 8-ої системи числення;
hex — встановлює при введенні/виведенні прапорець 16-ої системи числення;
ws — встановлює пропуск пробільних символів при введенні;
endl — при виведенні включає в потік символ нового рядка і вивантажує буфер;
ends — при виведенні включає в потік нульовий символ;
Приклад:
cout « 13 « hex « ' ' « 13 « oct « ' ' « 13 « endl;
Якщо інші значення прапорців встановлені за зaмoвчvвaнням, то буде виведено:
13 d 15