НОУ ІНТУЇТ | лекція | Організація введення-виведення в C ++

  1. 7.2 Робота з текстовими файлами в C ++ Текстовими називають файли, що складаються з будь-яких символів....
  2. 7.2.2 Читання інформації з текстового файлу

7.2 Робота з текстовими файлами в C ++

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

Для роботи з файлами використовуються спеціальні типи даних, звані потокамі4. Потік ifstream служить для роботи з файлами в режимі читання. Потік ofstream служить для роботи з файлами в режимі запису. Для роботи з файлами в режимі як читання, так і записи служить потік iofstream.

У програмах на C ++ при роботі з текстовими файлами необхідно підключати бібліотеки iostream і fstream.

Для того, щоб записати дані в текстовий файл, необхідно:

  1. Описати зміну типу ofstream.
  2. Відкрити файл за допомогою функції open.
  3. Вивести інформацію в файл.
  4. Закрити файл.

Для того, щоб вважати дані з текстового файлу, необхідно:

  1. Описати зміну типу ifstream.
  2. Відкрити файл за допомогою функції open.
  3. Зчитати інформацію з файлу, при зчитуванні кожної порції даних необхідно перевіряти чи досягнуто кінець файлу.
  4. Закрити файл.

7.2.1 Запис інформації в текстовий файл

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

ofstream F; 5

буде створена змінна F для запису інформації в файл. На наступному етапі файл необхідно відкрити для запису. У загальному випадку оператор відкриття потоку матиме вигляд:

Тут F - змінна, описана як ofstream, file - ім'я файлу на диску, mode - режим роботи з відкриваються файлом.

Файл може бути відкритий в одному з наступних режимів:

  • ios :: in - відкрити файл в режимі читання даних, цей режим є режимом за замовчуванням для потоків ifstream;
  • ios :: out - відкрити файл в режимі запису даних (при цьому інформація в існуючому файлі знищується), цей режим є режимом за замовчуванням для потоків ofstream;
  • ios :: app - відкрити файл в режимі запису даних в кінець файлу;
  • ios :: ate - пересунутися в кінець вже відкритого файлу;
  • ios :: trunc - очистити файл, це ж відбувається в режимі ios :: out;
  • ios :: nocreate - не виконувати операцію відкриття файлу, якщо він не существует6;
  • ios :: noreplace - не відкривати існуючий файл.

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

Після вдалого відкриття файлу (в будь-якому режимі) в змінної F буде зберігатися true, в іншому випадку false. Це дозволить перевіряти коректність операції відкриття файлу.

Відкрити файл (як приклад візьмемо файл abc.txt) в режимі запису можна одним з таких способів:

// Перший спосіб. ofstream f; f.open ( "abc.txt", ios :: out); // Другий спосіб, // режим ios :: out є режимом за замовчуванням для потоку ofstream ofstream f; f.open ( "abc.txt") // Третій спосіб об'єднує опис змінної типу потік // і відкриття файлу в одному операторі ofstream f ( "abc.txt", ios :: out);

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

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

Наприклад, для запису в потік F змінної a оператор виведення матиме вигляд:

Для послідовного виведення в потік G змінних b, c і d оператор виведення стане таким:

Закриття потоку здійснюється за допомогою оператора:

Як приклад розглянемо наступну задачу.

Завдання 7.1. Створити текстовий файл abc.txt і записати туди n дійсних чисел.

Текст програми з коментарями:

#include <iostream> #include <fstream> #include <iomanip> using namespace std; int main () {int i, n; double a; ofstream f; // Описує потік для запису даних в файл. f.open ( "abc.txt"); // Відкриваємо файл в режимі запису, // режим ios :: out встановлюється за умовчанням. cout << "n ="; cin >> n; // Введення кількості дійсних чисел. for (i = 0; i <n; i ++) {cout << "a ="; cin >> a; // Введення чергового числа. if (i <n-1) // Якщо число не останнє, f << a << "\ t"; // записати в файл це число і символ табуляції, інакше else f << a; // записати тільки число. } F.close (); // Закриття потоку. return 0; }

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

if (i <n-1) f << a << "\ t"; else f << a;

Тут реалізована помилки під час введення останнього числа. Після нього символ табуляції відсутня.

В результаті роботи програми буде створено текстовий файл abc.txt, який можна переглянути засобами звичайного текстового редактора ( Мал. 7.1 , Мал. 7.2 ).

7.2.2 Читання інформації з текстового файлу


Мал.7.1.

Процес роботи програми до задачі 7.1. Введення вихідних даних.

Для того, щоб прочитати інформацію з текстового файлу, необхідно описати змінну типу ifstream. Після цього файл необхідно відкрити для читання за допомогою оператора open. Якщо змінну назвати F, то перші два оператора будуть такими:

ifstream F; F.open ( "abc.txt", ios :: in);

8

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

Наприклад, для читання з потоку F в змінну a оператор введення матиме вигляд:

Для послідовного введення з потоку G в змінні b, с і d оператор введення стане таким:

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

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

Тут F - ім'я потоку, функція повертає логічне значення: true - якщо досягнуто кінець файлу, якщо не досягнуть функція повертає значення false.

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

while (! f.eof ()) // Організовано цикл, умовою закінчення циклу // є досягнення кінця файлу, в цьому випадку f.eof () поверне true. {F >> a; // Читання чергового значення з потоку F в змінну a. ... <обробка значення змінної a>}

Розглянемо наступну задачу.

Завдання 7.2. У текстовому файлі Завдання 7 зберігаються речові числа ( Мал. 7.2 ), Вивести їх на екран і обчислити їх кількість.

Текст програми з коментарями наведено нижче.

#include <iostream> #include <fstream> using namespace std; int main () {ifstream f; // Потік для читання. float a; int n = 0; f.open ( "abc.txt"); // Відкриваємо файл в режимі читання. if (f) // Якщо відкриття файлу пройшло коректно, то {while (! f.eof ()) // Організовано цикл, виконання циклу // перерветься, коли буде досягнутий кінця файлу. {F >> a; // Читання чергового значення з потоку f в змінну a. cout << a << "\ t"; // Висновок значення змінної a n ++; // Збільшення кількості лічених чисел. } F.close (); // Закриття потоку. cout << "n =" << n << endl; // Висновок на екран кількості чисел. } Else cout << "Файл не знайдено" << endl; // Якщо відкриття файлу пройшло некоректно, то // виведення повідомлення, про відсутність такого файлу. return 0; }

Результат роботи програми до задачі 7.2:

3.14159 2.789 -21.14 543.89 -90.1 n = 5

Програма працює коректно, якщо текстовий файл abc.txt був створений за допомогою програми до задачі 7.1. Припустимо, що файл створювався в текстовому редакторі, і користувач ввів після останньої цифри символ пробілу, табуляції або переходу на новий рядок. Тоді результат буде таким:

3.14159 2.789 -21.14 543.89 -90.1 -90.1 n = 6

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

while (! f.eof ()) {f >> a; if (! f.eof ()) // Перевіряємо, чи досягнуто кінець файлу, якщо немає - друкуємо значення a {cout << a << "\ t"; n ++; }}

Якщо кількість дійсних чисел, записаних в файл, відомо заздалегідь, то текст програми можна переписати таким чином:

#include <iostream> #include <fstream> using namespace std; int main () {ifstream f; float a; int i, n = 5; f.open ( "abc.txt"); if (f) {for (i = 1; i <= n; f >> a, cout << a << "\ t", i ++); f.close (); } Else cout << "Файл не знайдено" << endl; return 0; }

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

Завдання 7.3. У файлі Завдання 7 ( Мал. 7.2 ) Зберігається масив дійсних чисел, дописати в файл цей же масив, упорядкувавши його по зростанню.

Алгоритм розв'язання задачі дуже простий. Прочитуємо в масив дані з текстового файлу, упорядковуємо масив, дописуємо його в цей же файл.

Для читання даних з файлу описуємо потік ifstream, відкриваємо його в режимі читання і послідовно, поки не досягнемо кінця файлу, зчитуємо всі елементи в масив. Сортування проведемо методом бульбашки. Зверніть увагу, що потік потрібно відкрити так, щоб була можливість дописати в кінець файлу упорядкований масив.

Текст програми з коментарями наведено нижче.

#include <iostream> #include <fstream> using namespace std; int main () {ifstream f; // Потік для читання. ofstream g; // Потік для запису. float * a, b; a = new float [100]; int i, j, n = 0; f.open ( "abc.txt", ios :: in); // Відкриваємо файл в режимі читання. if (f) {while (! f.eof ()) {f >> a [n]; n ++; } // Сортування масиву. for (i = 0; i <n-1; i ++) for (j = 0; j <ni -1; j ++) if (a [j]> a [j +1]) {b = a [j]; a [j] = a [j + 1]; a [j +1] = b; } F.close (); // Закриваємо потік для читання. g.open ( "abc.txt", ios :: app); // Відкриваємо потік для того, щоб дописати дані. g << "\ n"; // Запис у файл символу кінця рядка for (i = 0; i <n; i ++) // Запис у файл if (i <n-1) g << a [i] << "\ t"; // елементу масиву і символу табуляції. else g << a [i]; // Запис останнього елемента масиву g.close (); // Закриття файлу. } Else cout << "Файл не знайдено" << endl; delete [] a; return 0; }

Вміст файлу abc.txt після запуску програми до задачі 7.3

3.14159 2.798 -21.14 543.89 -90.1 -90.1 -21.14 2.798 3.14159 543.89