Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
+ООП_Навч_посібник.doc
Скачиваний:
7
Добавлен:
01.07.2025
Размер:
6.58 Mб
Скачать

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() необхідно вдаватися у випадку, якщо програма призначена для роботи в несприятливих середовищах (для яких характерні часті відключення, наприклад, електрики).