Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Робота з текстовими файлами з використанням потоків






Теоретичні основи

Зовнішнє ім’я файлу зазначається з урахуванням методики його по­дання для операційної системи. Воно може бути подане в повному вигляді (диск, шлях, ім’я: " C: \\Users\\a.txt") або в скороченому – з ураху­ванням принципів умовчання, що закладені в роботу операційної системи, а саме:

· якщо не зазначене ім’я диска, то розглядається активний диск;

· якщо не зазначений шлях до файлу, то розглядається поточна папка (поточний каталог);

· якщо шлях починається не із символу \, то відлік шляху почи­на­ється з поточної папки (слід пам’ятати про те, що в C++ символ \ є управляючим і в разі необхідності його подання він подвою­ється: '\\').

Потокове введення/виведення

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

При роботі з файлами потік можна розглядати як файл разом із за­собами буферизації.

Використовуючи потоки можна:

· створювати файли і знищувати файли;

· відкривати і закривати файли;

· приєднувати файл до потоку і від’єднувати потік від файлу;

· здійснювати обмін даними між пам’яттю і файлом за допомогою потоку;

· аналізувати помилки потокового введення/виведення і умову до­сягнення кінця потоку (файлу);

· керувати буферизацією;

· керувати покажчиком поточної позиції у потоці.

Якщо потік відкритий, то з ним зв’язується так званий покажчик (ін­дикатор) поточної позиції. Читання/записування даних здійснюється почи­наючи з того байту файлу, на який вказує цей покажчик. При цьому покажчик поточної позиції автоматично «переміщається» по потоку на ту кількість байт, що відповідає зчитаному/записаному обсягу інформації. Результатом є те, що наступний сеанс читання/записування здійснювати­меться з орієнтацією на нове положення покажчика поточної позиції.

Робота з текстовими файлами з використанням потоків

Одним із видів файлів, якими може оперувати програма, написана мовою C++, є текстові файли, що складаються з символьних рядків змін­ної довжини, завершуваних спеціальною комбінацією символів, назива­ною «кінцем рядка». Комбінація «кінець рядка» складається з двох симво­лів – «повернення каретки» ('\xD', десятковий код 13) і «переведення рядка» ('\xA', десятковий код 10). Крім фізичного кінця файлу, як озна­ка кінця файлу в текстових файлах сприймається символ «кінець файлу» ('\x1A', десятковий код 26). Такий файл можна підготувати будь-яким текстовим редактором, у тому числі редактором, що вбудований в інтегро­ване середовище Visual Studio.

Якщо потік відкритий у текстовому режимі, то прочитана з нього послідовність символів «повернення каретки» і «переведення рядка» пере­творюється на символ нового рядка '\n' (значення 10). При записуванні в потік здійснюється зворотне перетворення.

У C++ потоки для роботи з файлами створюються як об’єкти наступ­них класів:

ofstream – для виведення (записування) даних у файл;

ifstream – для введення (читання) даних з файлу;

fstream – для читання і для запису даних (двонаправлений обмін).

Щоб використовувати ці класи, у текст програми необхідно вклю­чити додатковий заголовний файл fstream. Після цього в програмі можна визначати конкретні файлові потоки відповідних типів (об’єкти класів ofstream, ifstream, fstream), наприклад, так:

ifstream inFile; // Визначається вхідний

// файловий потік

ofstream outFile; // Визначається вихідний

// файловий потік

fstream ioFile; // Визначається файловий потік

// для введення і виведення

Створення файлового потоку (об’єкту відповідного класу) зв’язує ім’я потоку з виділеним для нього буфером і ініціалізує змінні стану по­току.

Створивши файловий потік, можна «приєднати» його до конкрет­ного файлу за допомогою компонентної функції open(). З її допомогою можна не тільки відкрити файл, але і зв’язати його з вже визначеним потоком. Формат цієї функції такий:

void open(const char * ім’я_файлу,

int режим = значення_за_умовчанням,

int захист = значення_за_умовчанням);

Перший параметр – ім’я_файлу – це ім’я вже існуючого або створю­ваного наново файлу. Це рядок, що визначає повне або скорочене ім’я файлу у форматі, регламентованому операційною системою. Другий пара­метр – режим – це диз’юнкція прапорів, які визначають режим роботи з відкриваним файлом (наприклад, тільки запис або тільки читання). Нижче наведено прапори режиму роботи для текстових файлів:

ios:: in = 0x01 – відкрити існуючий файл тільки для читання;

ios:: out = 0x02 – відкрити новий файл тільки для записування (якщо файл з ім’ям, указаним у третьому параметрі, вже існує, то він буде знищений і створений наново);

ios:: ate = 0x04 – при відкритті потоку покажчик поточної позиції встановлюється на кінець файлу; читати/писати можна в будь-якій позиції залежно від того, де розміщується покажчик поточної позиції, якщо його примусово перемістити;

ios:: арр = 0x08 – завжди дописувати дані в кінець існуючого файлу (якщо файл з ім’ям, указаним у третьому параметрі, вже існує, то він буде створений);

ios:: trunc = 0x10 – замість існуючого створювати новий файл (режим діє за умовчанням, якщо не вказано ios:: in, ios:: ate або ios:: арр);

ios:: nocreate = 0x20 – не відкривати новий файл; якщо файл відсутній генерується помилка;

ios:: noreplace = 0x40 – не відкривати існуючий файл; для існуючого вихідного файлу при відсутності режимів ios:: ate або ios:: арр генерується помилка.

Другий параметр (тільки разом з третім) може бути опущений. У цьому випадку береться його значення за умовчанням, що залежить від типу потоку, для якого викликається функція open(). Для ifstream‑ потоку таким значенням є ios:: in, а для ofstream‑ потоку – ios:: out. Для потоків класу fstream другий аргумент функції open() повинен бути заданий явно, оскільки неясно, у якому напрямку передбачається виконувати обмін з потоком (ios:: in – тільки для чи­тання, ios:: out – тільки для запису, ios:: in | ios:: out – двона­правлений обмін для існуючого файлу, ios:: app | ios:: in – для дозаписування з можливістю читання).

Для потоків класів ofstream і fstream, якщо в режимі відкриття вказано прапор ios:: app, незалежно від наявності прапорів ios:: out та ios:: in виведення здійснюється тільки в кінець файлу, не зважаючи на положення поточного покажчика потоку.

Третій параметр функції open() визначає захист файлу і звичайно встановлюється за умовчанням.

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

ім’я_об’єкту_класу.виклик_функції_що_належить_класу

Таким чином, відкриття і приєднання файлу до конкретного файло­вого потоку забезпечується таким викликом функції open():

ім’я_потоку.open(ім’я_файлу, режим, захист);

Тут ім’я_потоку – це ім’я одного з об’єктів, що належать класам ofstream, ifstream або fstream.

Приклади викликів функції open() для визначених вище потоків:

outFile.open(" С: \\USERS\\result.txt");

inFile.open(" data.txt");

ioFile.open(" change.txt", ios:: out);

При відкритті файлів з потоками класу ofstream другий параметр за умовчанням встановлюється рівним ios:: out, тобто файл відкрива­ється тільки для виведення. Таким чином, файл C: \USERS\result.txt після вдалого виконання функції open() буде при необхідності (якщо він не існував раніше) створений, а потім відкритий для виведення (запису) даних у текстовому режимі обміну і приєднаний до потоку outFile. Після цього до потоку outFile може застосовуватися, наприклад, опе­рація включення < <. Так, оператор

outFile < < -56 < < '\t' < < 3.1415;

записує два числа (ціле і дійсне) у файл C: \USERS\result.txt з розді­ленням їх символом табуляції.

Потік inFile класу ifstream у наведеному прикладі приєдну­ється функцією open() до файлу з ім’ям data.txt. Цей файл відкрива­ється для читання з нього даних у текстовому режимі. Якщо файл з ім’ям data.txt не існує, то спроба викликати функцію inFile.open() при­зведе до помилки. До потоку inFile після його відкриття може застосо­вуватися операція витягання > >. Так, за умови, що в програмі визначені змінні k (наприклад, типу int) і d (типу double), оператор

inFile > > k > > d;

уводить з файлу data.txt два числа, записуючи їх у змінні k і d з авто­матичним перетворенням до типів int і double відповідно.

Для перевірки вдалості завершення функції open() до потоку за­стосовують операцію!. Вираз! ім’я_потоку має ненульове значення за наявності помилки у відкритті потоку і дорівнює нулю, якщо помилки не було. Таким чином, результат вико­нання функції open() можна, напри­клад, перевірити так:

if (! inFile)

{

// Дії при помилці

}

Файл change.txt у прикладі, що наводився вище за текстом, від­кривається для записування і зв’язується з потоком ioFile, який буде вихідним потоком до тих пір, поки за допомогою повторного відкриття файлу явно не зміниться напрямок обміну з файлом або потоком. Щоб змінити режими доступу до файлу, його потрібно попередньо закрити за допомогою функції close().

Закриття файлу, приєднаного до будь-якого потоку, здійснюється функцією без параметрів close(); наприклад:

ioFile.close();

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

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

void clear(int = 0); – встановлює стан помилки потоку в нуль;

bool eof(); – повертає значення true (ненульове значення), якщо має місце умова кінця файлу (раніше було прочитано ознаку кінця файлу). Будь-який символ, що залишався в потоці, у тому числі символ нового рядка (але не символ кінця файлу) генерує значення false;

int get(); – передає із вхідного потоку наступний символ або значення EOF;

int get(char& змінна); – передає із вхідного потоку наступний символ і поміщає його в байт, на який указує параметр;

int get(char *рядок, int макс_кількість, char обмежувач = '\n'); – передає із вхідного потоку не більше макс_кількість символів і поміщає ці символи в область пам’яті, на яку вказує перший параметр, з дописуванням до прочитаного рядка кінцевого символу '\0'; третій па­раметр визначає обмежувач, при досягненні якого припиняється читання (обмежувач не вилучається з файлу; третій параметр може бути опуще­ний, що відповідає використанню як обмежувача символу '\n');

istream& getline(char *рядок, int макс_кількість, char обмежувач = '\n'); – аналогічна функції get() з тією ж кіль­кістю параметрів, але символ‑ обмежувач вилучається із файлу без зане­сення в рядок;

istream& ignore(int кількість, int роздільник); – пропускає символи в кількості, заданій першим параметром, зупиняючись, якщо зустрінеться символ-роздільник;

int peek(); – читає з потоку (але не вилучає) наступний символ, повертаючи зчитаний символ або EOF, якщо має місце умова кінця файлу;

istream& read(char *рядок, int кількість); – читає задану другим параметром кількість символів (точніше не більше цього парамет­ру), поміщаючи їх у масив, заданий першим параметром;

istream& seekg(streampos позиція); – установлює покажчик поточної позиції на абсолютну позицію, задану параметром;

istream& seekg(streamoff зсув, seek_dir відлік); – пе­реміщає в потоці покажчик поточної позиції читання на число байт, задане першим параметром відносно другого параметру (0 == ios:: beg – початок потоку, 1 == ios:: cur – поточна пози­ція, 2 == ios:: end – кінець потоку);

streampos tellg(); – повертає поточну позицію читання;

Деякі функції, що використовуються при виведенні:

ostream& put(char символ) – поміщає один символ у потік;

ostream& seekp(streampos позиція); – аналог seekg() з одним параметром;

ostream& seekp(streamoff зсув, seek_dir відлік); – ана­лог функції seekg() з двома параметрами;

ostream& write(char *рядок, int кількість); – поміщає в по­тік кількість символів з параметра рядок;

streampos tellp(); – повертає поточну позицію записування;

Відзначимо, що при оголошенні деяких з наведених вище функцій використані спеціальні типи, а саме, streampos (аналогом є тип ios:: pos_type) і streamoff. Указані типи замінюють раніше вико­ристовуваний у відповідних функціях тип long, причому оговорюється, що використання замість них типу long є не досить коректним.

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

while (ioFile. peek()! = EOF)

{ // Дії по введенню і обробці елемента даних

}

Якщо файл відкритий і для введення, і для виведення (двонаправ­лений обмін), то в разі потреби переходу від уведення до виведення (або навпаки) необхідно виконати примусове зміщення покажчика поточної позиції файлу (як варіант – на 0 байт відносно поточної позиції).

При роботі з файлами (будь-якими, а не тільки текстовими) корис­ними можуть бути такі дві функції, оголошені в заголовному файлі io.h:

int remove(const char *шлях); – знищення файлу, ім’я якого задане як параметр (файл повинен бути закритим);

int rename(const char *старе_ім’я, const char * нове_ім’я); – перейменування файлу або каталогу (файл повинен бути закритим). Якщо в новому імені файлу вказати інший шлях відносно ста­рого, файл буде перенесений. Каталог перенести неможливо.






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.