Студопедия

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

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

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






Робота з бінарними файлами

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

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

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

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

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

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

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

Потік – це файл разом із засобами буферизації. При роботі з потоком можна:

· відкривати і закривати потоки (зв’язувати потоки з конкретними файлами);

· вводити і виводити дані;

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

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

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



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

Робота з бінарними файлами

Взагалі кажучи, файли зберігаються в бінарному (двійковому) фор­маті і тільки режим відкриття визначає, як програма повинна інтерпре­тувати вміст файлу. Текстовий режим є режимом за умовчанням, і в цьому режимі окремо інтерпретується послідовність з двох символів – «повер­нення каретки» ('\xD', десятковий код 13) і «переведення рядка» ('\xA', десятковий код 10). Бінарний режим відкриття файлу забезпечує сприйняття всіх символів окремо, у тому числі й символів '\xD' і '\xA'. Бінарні файли не створюються текстовими редакторами, але мо­жуть бути створені за допомогою засобів мови C++ (або C).

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Щоб вказати про необхідність відкриття файлу в бінарному режимі при виклику функції open() її другий параметр за допомогою диз’юнк­ції комбінується з таким прапором:

ios:: binary = 0x80 – відкрити файл у бінарному режимі.

Таким чином, найпростішими режимами відкриття для бінарних файлів є:

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

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

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

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

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

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

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

Режим відкриття може бути заданий значенням ios:: binary без комбінування з іншими прапорами. У цьому випадку ifstream‑ поток відкривається тільки для читання (ios:: in | ios:: binary), а ofstream‑ потоку – тільки для запису (ios:: out | ios:: binary).

Для потоків класу fstream другий аргумент функції open() повинен бути заданий явно, оскільки неясно, у якому напрямку перед­бачається виконувати обмін з потоком: ios:: in | ios:: binary – тільки для читання, ios:: out | ios:: binary – тільки для запису, ios:: in | ios:: out | ios:: binary – двонаправлений обмін для існуючого файлу (аналог режиму " r+"). Якщо ж встановлена комбінація прапорів ios:: in | ios:: out | ios:: trunc | ios:: binary, то вона забезпечує відкриття нового файлу для записування і читання (аналог режиму " w+" для мови Сі).

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

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

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

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

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

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

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

Приклади відкриття бінарних файлів:

#include < iostream>
#include < fstream>
// Текст програми
ifstream inFile;
ofstream outFile;
fstream ioFile;
// Текст програми
inFile.open(" a.dat", ios:: binary);
char OutFileName[] = " C: \\USERS\\result.dbl";
outFile.open(OutFileName, ios:: binary);
char *FileName = new char [256];
cout < < " \nInput the name of new file\n";
cin.getline(FileName, 256);
ioFile.open(FileName, ios:: in | ios:: out |
ios:: binary);

Потік inFile класу ifstream у наведеному прикладі приєдну­ється функцією open() до файлу з ім’ям a.dat. Цей файл відкривається для читання з нього даних у бінарному режимі. Якщо файл з ім’ям a.dat не існує, то спроба викликати функцію inFile.open() призведе до по­милки.

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

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

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

if (! inFile)

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

}

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

ioFile.close();

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

Для введення/виведення даних при роботі з бінарними файлами ви­користовують такі функції:

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

ostream& write(char *рядок, int кількість); – поміщає в по­тік символи з області пам’яті, що адресується першим параметром, у кіль­кості, яка визначається другим параметром.

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

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

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

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

Для описаного вище потоку ioFile це можна зробити, наприклад, так:

while (ioFile. peek()! = EOF)

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

}

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

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

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

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

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

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

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

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

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

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

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

Можливі також уведення/виведення окремих символів за допомогою таких функцій:

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

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

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

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

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

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

<== предыдущая лекция | следующая лекция ==>
a → b/ c-d | 




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