Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Не підтверджено.doc
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
3 Мб
Скачать
☆
  1. Використання функції eof() для виявлення кінця файлу

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

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

У наведеному нижче коді програми для виведення на екран вмісту файлу ви­користовується функція eofO-

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

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

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

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

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

{

char ch; if(argc != 2) {

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

}

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

if(ün) {

cout«"Не вдається відкрити файл" « endl; return 1;

}

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

If(!in.Eof()) cout« ch;

}

In.CloseO; getchO; return 0;

}

  1. Застосування C++ файлової системи для порівняння файлів

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

Код програми 9.17. Демонстрація механізму застосування файлової системи для порівняння файлів #include <iostream> // Для потокового введення-виведення

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

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

Int main(int arge, char *argv[])

{

register int i;

unsigned char buf1 [1024], buf2[1024]; if(argc !=3) {

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

}

Ifstream f1(argv[1], ios::in | ios::binary); if(!f1) {

cout«"He вдається відкрити перший файл" « endl; return 1;

}

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

if(!f2){

cout«"Не вдається відкрити другий файл" « endl; return 1;

}

cout«"Порівняння файлів" « endl; do {

f1 ,read((char *) buf1, sizeof buf1); f2.read((char*) buf2, sizeof buf2); if(f1 gcountO != f2.gcount0) {

cout«"Файли мають різні розміри"« endl; fi cioseO; f2.close0; getchO; return 0;

}

// Порівняння вмісту буферів. for(i=0; i<f1 ,gcount(); І++) if(buf1[i]!=buf2[i]){

cout«"Файли різні"« endl; f1 .cioseO; f2.close0; getchO; return 0;

}

} while(!f1 .eofO && !f2.eof0);

cout«"Файли однакові" « endl;

f1.close(); f2.close(); getchO; return 0;

}

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

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

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

istream &get(char*buf, streamsize пит);

istream &get(char*buf, streamsize пит, char delim);

int getO;

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

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

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

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

Код програми 9.18. Демонстрація механізму використання функції get() для зчитування рядків, що містять пропуски #include <iostream> // Для потокового введення-виведення

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

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

int mainO

{

char str[80];

cout«"Введіть ім'я: cin.get(str, 79);

cout« str« endl; getchO; return 0;

}

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

Розглянемо ще одну функцію, яка дає змогу вводити дані. Йдеться про фун­кцію getlineO, яка є членом кожного потокового класу, призначеного для введення інформації. Ось як виглядають прототипи версій цієї функції: istream &getline(char *buf, streamsize num);

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

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

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

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

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

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

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

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

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

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

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

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

Ім'я

Значення

ios::goodbit

Помилок немає

ios: :eofbit

1 внаслідок виявлення кінця файлу; 0 - в іншому випадку

ios: :failbit

1 під час виникнення поправної помилки введення-виведення; 0 - в ін­шому випадку

ios: :badbit

1 під час виникнення непоправної помилки введення-виведення; 0 - в іншому випадку

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

Функція rdstate() повертає поточний статус опцій помилок. Неважко здогада­тися, що, судячи з наведеного вище переліку опцій, функція rdstate() поверне зна­чення good bit за відсутності будь-яких помилок. У іншому випадку вона повертає відповідний код помилки.

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

  • функція bool bad(); повертає значення ІСТИНА, якщо внаслідок виконання операції введення-виведення даних було встановлено опцію badbit;

  • функцію bool eof(); розглянуто вище;

  • функція bool failO; повертає значення ІСТИНА, якщо внаслідок виконання операції введення-виведення даних було встановлено опцію failbit;

  • функція bool good(); повертає значення ІСТИНА, якщо у процесі виконання операції введення-виведення даних помилок не відбулося.

У інших випадках ці функції повертають значення ФАЛЬШ.

Якщо у процесі виконання операції введення-виведення даних Ви допустили­ся помилки, то, можливо, перш ніж продовжувати виконання програми, є сенс скинути опції помилок. Для цього використовують функцію clearO (член класу ios), прототип якої має такий вигляд: void clear(iostate Hags = ios::goodbit);

Якщо параметр flags дорівнює значенню goodbit(BOHO встановлюється за за­мовчуванням), то всі опції помилок очищаються. Інакше опції встановлюються відповідно до заданого Вами значення.

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

  1. Використання файлів довільного доступу

Дотепер використовувалися файли, доступ до вмісту яких було організовано строго послідовно, байт за байтом. Але у мові програмування C++ також можна отримувати доступ до файла у довільному порядку.

  1. Функції довільного доступу

Для довільного доступу до даних файла необхідно використовувати функції seekg() і seekpO- їх прототипи мають такий вигляд:

istream &seekg(off_type offset, seekdir origin)',

ostream &seekp(off_type offset, seekdir origin)',

Використовуваний тут цілочисельний тип off_type (його визначено у класі ios) дає змогу зберігати найбільше допустиме значення, яке може мати параметр offset. Тип seekdir визначено як перерахунок, який має такі значення.

Значення

Опис

ios::beg

Початок файлу

ios::cur

Поточна позиція файлу

ios::end

Кінець файлу

У С++-системі введення-виведення передбачено можливість керування двома покажчиками, пов'язаними з файлом. Ці так звані get- і put-покажчики визначають, у якому місці файлу повинна виконатися наступна операція введення та виведен­ня відповідно. При кожному виконанні операції введення або виведення відповід­ний покажчик автоматично переміщається у вказану позицію. Використовуючи функції seekgO і seekpO, можна отримувати доступ до файла у довільному порядку.

  1. Функція seekg() переміщає поточний get-покажчик відповідного файлу на offset байт відносно позицій, які задаються параметром origin.

  2. Функція seekp() переміщає поточний put-покажчик відповідного файлу на offset байт відносно позицій, які задаються параметром origin.

Існують перевизначені версії функцій seekgO і seekpO, які переміщають фай­лові покажчики у позиції файлу, що задаються значеннями, які повертаються фун­кціями tellg() і (еІІрОвідповідно. Ось як виглядають їх прототипи: istream &seekg(pos_type position)', ostream &seekp(pos_type position)',

  1. Приклади використання довільного доступу до вмісту файлу

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

  • конкретний байт, який потрібно у ньому змінити. Програма потім записує у вка­зану позицію символ "X". Зверніть увагу на те, що оброблюваний файл повинен бути відкритим для виконання операцій зчитування-запису.

Код програми 9.19. Демонстрація механізму використання функції seekpO для довільного доступу до вмісту файлу #include <iostream> // Для потокового введення-виведення

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

#include <cstdlifc» // Для використання бібліотечних функцій

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

int main(int arge, char 1argv[])

{

if(argc !=3) {

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

}

fstream out(argv[1], ios::in | ios::out | ios::binary); if(!out) {

cout«"He вдається відкрити файл" « endl; return 1;

}

out.seekp(atoi(argv[2]), ios::beg);

out.put('X'); out.closeO; getchO; return 0;

}

У наведеному нижче коді програми показано приклад використання функції seekgO- Вона відображає вміст файлу, починаючи з позиції, що задається у коман­дному рядку.

Код програми 9.20. Демонстрація механізму відображення вмісту файлу із заданої позиції #include <iostream> // Для потокового введення-виведення

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

#include <cstdlib> // Для використання бібліотечних функцій

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