Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Namespace CounterNameSpace 12 страница




Рекомендщується також перевірити факт успішного відкриття файлу за допомогою функції is_open (), яка є членом класів fstream, ifstream і ofstream. Ось її прототип:

bool is_open ();

Ця функція повертає значення ІСТИНА, якщо потік пов'язаний з відкритим файлом, і ФАЛЬШ – в іншому випадку. Наприклад, використовуючи такий фрагмент коду програми, можна дізнатися про те, чи відкрито у даний момент потоковий об'єкт myStream:

if (!myStream. is_open ()) {

cout << "Файл не відкрито.\n";

//...

}

Хоча цілком коректно використовувати функцію open () для відкриття файлу, проте здебільшого це робиться по-іншому, оскільки класи ifstream, ofstream і fstream містять конструктори, які автоматично відкривають заданий файл. Параметри у цих конструкторів і їх значення (що діють за замовчуванням) збігаються з параметрами і відповідними значеннями функції open (). Тому найчастіше файл відкривається так, як це показано в наведеному нижче прикладі:

ifstream myStream("myFile"); // Файл відкривається для введення

Якщо з деякої причини файл відкрити неможливо, то потоковій змінній, що пов'язується з цим файлом, встановлюється значення, що дорівнює ФАЛЬШ.

Щоб закрити файл, використовується функція close ().

Щоб закрити файл, використовується функція-член close (). Наприклад, щоб закрити файл, який є пов'язаним з потоковим об'єктом myStream, потрібно використати таку настанову:

myStream. close ();

Функція close () не має параметрів і не повертає ніякого значення.

19.5.2. Зчитування і запис текстових файлів

Найпростіше зчитувати дані з текстового файлу або записувати їх до нього за допомогою операторів "<<" і ">>". Наприклад, у наведеному нижче коді програми виконується запис у файл test цілого числа, значення з плинною крапкою і рядка.

Код програми 19.11. Демонстрація запису даних у файл

#include <iostream> // Для потокового введення-виведення

#include <fstream> // Для роботи з файлами

using namespace std; // Використання стандартного простору імен

 

int main ()

{

ofstream out ("test");

if (! out) {

cout << "Не вдається відкрити файл.\n";

return 1;

}

 

out << 10 << " " << 123.23 << "\n";

out << "Це короткий текстовий файл.";

 

out. close ();

 

getch (); return 0;

}

Наведений нижче код програми зчитує ціле число, float -значення, символ і рядок з файлу, створеного у процесі виконання попередньою програмою:

Код програми 19.12. Демонстрація зчитування даних з файлу

#include <iostream> // Для потокового введення-виведення

#include <fstream> // Для роботи з файлами

using namespace std; // Використання стандартного простору імен

 

int main ()

{

char ch;

int izm;

float f;

char strMas[80];

 

ifstream in ("test");

if (! in) {

cout << "Не вдається відкрити файл.\n";

return 1;

}

 

in >> izm;

in >> f;

in >> ch;

in >> strMas;

 

cout << izm << " " << f << " " << ch << "\n";

cout << strMas;

 

in. close ();

 

getch (); return 0;

}

Варто знати! Під час використання перевантаженого оператора ">>" для зчитування даних з текстових файлів відбувається перетворення деяких символів. Наприклад, "пропускні" символи опускаються. Якщо необхідно запобігти будь-яким перетворенням символів, то потрібно відкрити файл у двійковому режимі доступу до його даних.

Необхідно пам'ятати! Під час використання перевантаженого оператора ">>" для зчитування рядка введення даних припиняється внаслідок виявлення першого "пропускного" символу.

19.5.3. Неформатоване введення-виведення даних у двійковому режимі

Форматовані текстові файли (подібні тим, які використовувалися у попередніх прикладах) корисні в багатьох ситуаціях, але вони не мають гнучкості неформатованих двійкових файлів. Тому мова програмування C++ підтримує ряд функцій файлового введення-виведення у двійковому режимі, які можуть виконувати операції без форматування даних.

Для виконання двійкових операцій файлового введення-виведення необхідно відкрити файл з використанням специфікатора режиму ios:: binary. Необхідно відзначити, що функції, які використовуються для оброблення неформатованих файлів, можуть також виконувати дії з файлами, відкритими в текстовому режимі доступу, але при цьому використовується перетворення символів, яке зводить нанівець основну мету виконання двійкових файлових операцій.

Функція get () зчитує символ з файлу, а функція put () записує символ у файл.

У загальному випадку існує два способи запису неформатованих двійкових даних у файл і зчитування їх з файлу. Перший спосіб полягає у використанні функції-члена класу put () (для запису байта у файл) і функції-члена класу get () (для зчитування байта з файлу). Другий спосіб передбачає застосування "блокових" С++-функцій введення-виведення read () і write (). Розглянемо кожен спосіб окремо.

Функції get () і put () мають багато форматів, але найчастіше використовуються такі їх версії:

istream & get (char &ch);

ostream & put (char ch);

1. Функція get () зчитує один символ з відповідного потоку і поміщає його значення у змінну ch. Вона повертає посилання на потік, що є пов'язаним із заздалегідь відкритим файлом. Досягнувши кінця цього файлу, значення посилання дорівнюватиме нулю.

2. Функція put () записує символ ch у потік і повертає посилання на цей потік.

У процесі виконання наведеної нижче програми на екран буде виведено вміст будь-якого заданого файлу. Тут використовується функція get ().

Код програми 19.13. Демонстрація відображення вмісту файлу за допомогою функції get()

#include <iostream> // Для потокового введення-виведення

#include <fstream> // Для роботи з файлами

using namespace std; // Використання стандартного простору імен

 

int main (int argc, char * argv [])

{

char ch;

 

if (argc!=2) {

cout << "Застосування: ім'я_програми <ім'я_файлу>\n";

return 1;

}

 

ifstream in (argv [1], ios:: in | ios:: binary);

if (! in) {

cout << "Не вдається відкрити файл.\n";

return 1;

}

 

while (in) { // Досягши кінця файлу потоковий

// об'єкт in прийме значення false.

in. get (ch);

if (in) cout << ch;

}

 

in. close ();

 

getch (); return 0;

}

Досягши кінця файлу, потоковий об'єкт in прийме значення ФАЛЬШ, яке зупинить виконання циклу while. Проте існує дещо коротший варіант коду програми організації циклу, призначеного для зчитування і відображення вмісту файлу:

while (in. get (ch)) cout << ch;

Цей варіант організації циклу також має право на існування, оскільки функція get () повертає потоковий об'єкт in, який, досягши кінця файлу, прийме значення false.

У наведеному нижче коді програми для запису рядка у файл використовується функція put ().

Код програми 19.14. Демонстрація механізму використання функції put() для запису рядка у файл

#include <iostream> // Для потокового введення-виведення

#include <fstream> // Для роботи з файлами

using namespace std; // Використання стандартного простору імен

 

int main ()

{

char *p = "Всім привіт!";

 

ofstream out ("test", ios:: out | ios:: binary);

 

if (! out) {

cout << "Не вдається відкрити файл.\n";

return 1;

}

while (*p) out. put (*p++);

 

out. close ();

 

getch (); return 0;

}

19.5.4. Зчитування і запис у файл блоків даних

Для зчитування і записування у файл блоків двійкових даних використовуються функції-члени read () і write (). Їх прототипи мають такий вигляд:

istream & read (char *buf, streamsize num|);

 

ostream & write (const char *buf, int streamsize num|);

1. Функція read () зчитує num байт даних з пов'язаного з файлом потоку і поміщає їх у буфер, яка адресується покажчиком buf.

2. Функція write () записує num байт даних у пов'язаний з файлом потік з буфера, яка адресується покажчиком buf.

Як ми вже зазначали вище, тип streamsize визначається як деякий різновид цілочисельного типу. Він дає змогу зберігати найбільшу кількість байтів, яка може бути передана у процесі будь-якої операції введення-виведення даних.

Функція read () вводить блок даних, а функція write () виводить його.

У процесі виконання наведеної нижче програми спочатку у файл записується масив цілих чисел, а потім його значення зчитується з файлу.

Код програми 19.15. Демонстрація механізму використання функцій read() і write()

#include <iostream> // Для потокового введення-виведення

#include <fstream> // Для роботи з файлами

using namespace std; // Використання стандартного простору імен

 

int main ()

{

int n[5] = {1, 2, 3, 4, 5};

register int i;

 

ofstream out ("test", ios:: out | ios:: binary);

if (! out) {

cout << "Не вдається відкрити файл.\n";

return 1;

}

 

out. write ((char *) &n, sizeof n);

 

out. close ();

for (i=0; i<5; i++) n[i] = 0; // Очищtyyz масивe

 

ifstream in ("test", ios:: in | ios:: binary);

if (! in) {

cout << "Не вдається відкрити файл.\n";

return 1;

}

 

in. read ((char *) &n, sizeof n);

for (i=0; i<5; i++) // Відображаємо значення, зчитані з файлу.

cout << n[i] << " ";

 

in. close ();

 

getch (); return 0;

}

Звернемо Вашу увагу на те, що в настановах звернення до функцій read () і write () виконуються операції приведення типу, які є обов'язковими під час використання буфера, що визначається у вигляді не символьного масиву.

Функція gcount () повертає кількість символів, зчитаних у процесі виконання останньої операції введення даних.

Якщо кінець файлу досягнуто ще до того моменту, як було зчитано num символів, то функція read () просто припинить своє виконання, а буфер міститиме стільки символів, скільки вдалося зчитати до цього моменту. Точну кількість зчитаних символів можна дізнатися за допомогою ще однієї функції-члена класу gcount (), яка має такий прототип:

streamsize gcount ();

Функція gcount () повертає кількість символів, зчитаних у процесі виконання останньої операції введення даних.

19.5.5. Виявлення кінця файлу

Виявити кінець файлу можна за допомогою функції-члена класу eof (), яка має такий прототип:

bool eof ();

Ця функція повертає значення true у випадку досягнення кінця файлу; інакше вона повертає значення false.

Функція eof () дає змогу виявити кінець файлу.

У наведеному нижче коді програми для виведення на екран вмісту файлу використовується функція eof ().

Код програми 19.16. Демонстрація виявлення кінця файлу за допомогою функції eof()

#include <iostream> // Для потокового введення-виведення

#include <fstream> // Для роботи з файлами

using namespace std; // Використання стандартного простору імен

 

int main (int argc, char * argv [])

{

char ch;

if (argc!= 2) {

cout << "Застосування: ім'я_програми <ім'я_файлу>\n";

return 1;

}

 

ifstream in (argv [1], ios:: in | ios:: binary);

if (! in) {

cout << "Не вдається відкрити файл.\n";

return 1;

}

 

while (! in. eof ()) { // Використання функції eof ()

in. get (ch);

if (! in. eof ()) cout << ch;

}

 

in. close ();

 

getch (); return 0;

}

19.5.6. Приклад порівняння файлів

Наведений нижче код програми ілюструє потужність і простоту застосування у мові програмування C++ файлової системи. Тут порівнюються два файли за допомогою функцій двійкового введення-виведення read (), eof () і gcount (). Програма спочатку відкриває порівнювані файли для виконання двійкових операцій (щоб не допустити перетворення символів). Потім з кожного файлу по черзі зчитуються блоки інформації у відповідні буфери і порівнюється їх вміст. Оскільки об'єм зчитаних даних може бути меншим за розмір буфера, то у програмі використовується функція gcount (), яка точно визначає кількість зчитаних у буфер байтів. Неважко переконатися у тому, що під час використання файлових С++-функцій для виконання цих операцій була потрібна зовсім невелика за розміром програма.

Код програми 19.17. Демонстрація механізму застосування файлової системи для порівняння файлів

#include <iostream> // Для потокового введення-виведення

#include <fstream> // Для роботи з файлами

using namespace std; // Використання стандартного простору імен

 

int main (int argc, char * argv [])

{

register int i;

 

unsigned char buf1[1024], buf2[1024];

if (argc!=3) {

cout << "Застосування: ім'я_програми <ім'я_файла1> "

<< "<ім'я_файла2>\n";

return 1;

}

 

ifstream f1(argv[1], ios::in | ios:: binary);

if (!f1) {

cout << "Не вдається відкрити перший файл.\n";

return 1;

}

 

ifstream f2(argv[2], ios::in | ios:: binary);

if (!f2) {

cout << "Не вдається відкрити другий файл.\n";

return 1;

}

 

cout << "Порівняння файлів.\n";

do {

f1. read ((char *) buf1, sizeof buf1);

f2. read ((char *) buf2, sizeof buf2);

if (f1. gcount ()!= f2. gcount ()) {

cout << "Файли мають різні розміри.\n";

f1. close ();

f2. close ();

getch (); return 0;

}

 

// Порівняння вмісту буферів.

for (i=0; i<f1. gcount (); i++)

if (buf1[i]!= buf2[i]) {

cout << "Файли різні.\n";

f1. close ();

f2. close ();

getch (); return 0;

}

} while (!f1. eof () &&!f2. eof ());

 

cout << "Файли однакові.\n";

 

f1. close ();

f2. close ();

 

getch (); return 0;

}

Проведіть експеримент. Розмір буфера у цій програмі жорстко встановлено таким, що дорівнює 1024. Як вправу замініть це значення const -змінної та випробуйте інші розміри буферів. Визначте оптимальний розмір буфера для свого операційного середовища.

19.5.7. Використання інших функцій для двійкового введення-виведення

Крім наведеного вище формату використання функції get () існують і інші її перевантажені версії. Наведемо прототипи для трьох з них, які використовуються найчастіше:

istream & get (char * buf, streamsize num);

 

istream & get (char * buf, streamsize num, char delim);

int get ();

1. Перша версія функції get () дає змогу зчитувати символи і заносити їх у масив, що задається параметром buf, доти, доки не буде зчитано num -1| символів, або не трапиться символ нового рядка, або не буде досягнуто кінець файлу. Після завершення роботи функції get () масив, яка адресується покажчиком buf, матиме завершальний нуль-символ. Символ нового рядка, якщо такий виявиться у вхідному потоці, не вилучається. Він залишається там доти, доки не виконається наступна операція введення-виведення.

2. Друга версія функції get () призначена для зчитування символів і занесення їх у масив, яка адресується покажчиком buf, доти, доки не буде зчитано num -1 символів, або не виявиться символ, який задається параметром delim, або не буде досягнуто кінець файлу. Після завершення роботи функції get () масив, яка адресується покажчиком buf, матиме завершальний нуль-символ. Символ-роздільник (заданий параметром delim), якщо такий виявиться у вхідному потоці, не вилучається. Він залишається там доти, доки не виконається наступна операція введення-виведення.

3. Третя перевантажена версія функції get () повертає з потоку наступний символ. Він міститься в молодшому байті значення, що повертається функцією. Отже, значення, що повертається функцією get (), можна присвоїти змінній типу char. Досягши кінця файлу, ця функція повертає значення EOF, яке визначено у заголовку < iostream >.

Функцію get () корисно використовувати для зчитування рядків, що містять пропуски. Як уже зазначалося вище, якщо для зчитування рядка використовують оператор ">>", то процес введення даних зупиняється внаслідок виявлення першого ж пропускного символу. Це робить оператор ">>" даремним для зчитування рядків, що містять пропуски. Але цю проблему, як це показано в такій програмі, можна обійти за допомогою функції get (buf, num).

Код програми 19.18. Демонстрація механізму використання функції get() для зчитування рядків, що містять пропуски

#include <iostream> // Для потокового введення-виведення

#include <fstream> // Для роботи з файлами

using namespace std; // Використання стандартного простору імен

 

int main ()

{

char strMas[80];

cout << "Введіть ім'я: ";

cin. get (strMas, 79);

cout << strMas << "\n";

 

getch (); return 0;

}

У цій програмі як символ-роздільник під час зчитування рядка за допомогою функції get () використовується символ нового рядка. Це робить поведінку функції get () багато в чому схожою з поведінкою стандартної функції gets (). Проте перевага функції get () полягає у тому, що вона дає змогу запобігти можливому виходу за межі масиву, який приймає символи, що вводяться користувачем, оскільки у програмі оголошено максимальну кількість зчитаних символів. Це робить функцію get () набагато безпечнішою за функцію gets ().

Розглянемо ще одну функцію, яка дає змогу вводити дані. Йдеться про функцію getline (), яка є членом кожного потокового класу, призначеного для введення інформації. Ось як виглядають прототипи версій цієї функції:

istream & getline (char *buf, streamsize num);

 

istream & getline (char *buf, streamsize num, char delim);

Функція getline () використовується як ще один спосіб введення даних.

1. Під час використання першої версії функції getline ()символи зчитуються і заносяться у масив, яка адресується покажчиком buf, доти, доки не буде зчитано num -1| символів, або не трапиться символ нового рядка, або не буде досягнуто кінець файлу. Після завершення роботи функції getline () масив, яка адресується покажчиком buf, матиме завершальний нуль-символ. Символ нового рядка, якщо такий виявиться у вхідному потоці, при цьому вилучається, але не заноситься у масив buf.

2. Друга версія функції getline ()призначена для зчитування символів і занесення їх у масив, яка адресується покажчиком buf, доти, доки не буде зчитано num -1 символів, або не виявиться символ, який задається параметром delim, або не буде досягнуто кінець файлу. Після завершення роботи функції getline () масив, яка адресується покажчиком buf, матиме завершальний нуль-символ. Символ-роздільник (які задаються параметром delim), якщо такий виявиться у вхідному потоці, вилучається, але не заноситься у масив buf.

Як бачите, ці дві версії функцій getline () практично ідентичні версіям get (buf, num) і get (buf, num, delim) функції get (). Обидві зчитують символи з вхідного потоку і заносять їх у масив, яка адресується покажчиком buf, доти, доки не буде зчитано num- 1 символів, або не виявиться символ, який задається параметром delim. Відмінність між функціями get () і getline () полягає у тому, що функція getline () зчитує і видаляє символ-роздільник з вхідного потоку, а функція get () цього не робить.

Функція peek () зчитує наступний символ з вхідного потоку, не видаляючи його.

Наступний символ з вхідного потоку можна отримати і не видаляти його з потоку за допомогою функції peek (). Ось як виглядає її прототип:

int peek ();

Функція peek () повертає наступний символ потоку, або значення EOF, якщо досягнуто кінець файлу. Зчитаний символ повертається в молодшому байті значення, що повертається функцією. Тому значення, що повертається функцією peek (), можна присвоїти змінній типу char.

Функція putback () повертає зчитаний символ у вхідний потік.

Останній символ, що зчитується з потоку, можна повернути у потік, використовуючи функцію putback (). Її прототип має такий вигляд:

istream & putback (char сh);

У цьому записі параметр сh містить символ, що зчитується з потоку останнім.

Функція flush () записує на диск вміст файлових буферів.

Під час виведення даних за допомогою функції flush ()не відбувається негайного їх запису на фізичний пристрій, що є у даний момент пов'язаним з потоком. Інформація, що підлягає виведенню, спочатку накопичується у внутрішньому буфері доти, доки він цілком не заповниться. І тільки тоді його вміст переписується на диск. Проте існує можливість негайного перезапису на диск даних, що зберігається в буфері функції flush (), не чекаючи його повного заповнення. Цей засіб полягає у виклику функції flush (). Її прототип має такий вигляд:

ostream & flush ();

До викликів функції flush () необхідно вдаватися у випадку, якщо програма призначена для роботи в несприятливих середовищах (для яких характерні часті відключення, наприклад, електрики).

19.5.8. Перевірка статусу введення-виведення

С++-система введення-виведення підтримує статусну інформацію про результати виконання кожної операції введення-виведення даних. Поточний статус потоку введення-виведення описується в об'єкті типу iostate, який є перерахунком (воно визначене у класі ios), що містить такі члени:




Поделиться с друзьями:


Дата добавления: 2014-11-29; Просмотров: 515; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.149 сек.