ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 22.12.2021

Просмотров: 140

Скачиваний: 2

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

Лекція 9.

Робота з файлами.

Дисковим файлом називають поіменований набір даних одного типу.

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

Типи дискових файлів.

Всі файли поділяються на два основні типи: текстові і двійкові (інакше бінарні), зв’язані з різними типами потоків даних. Згадаємо, що текстовий потік складається із послідовності ASCII кодів, представлених у вигляді рядків; кожний рядок завершується символом \n. Кінець текстового потоку помічається символом кінця файлу (^Z). Навпаки, двійковий потік являє собою послідовність бітів, данні двійкового не можна інтерпретувати зовні текста програми.

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

На будь-якому типу комп’ютера для роботи з файлами необхідні такі чотири кроки:

  1. Необхідно отримати доступ до потрібного файла. Це схоже на відкриття потрібної шафи з файлами. Ця операція має назву відкриття файлу.

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

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

  4. Після завершення роботи з файлом його потрібно звільнити. Цю операцію називають закриттям файлу; така операція аналогічна запиранню шафи і здачі ключа.

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

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

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


FILE *fopen(const char *file_name, const char *name);

Функції в якості аргументів потрібно передати два значення: покажчик на ім’я відкриваємого файлу file_nameі покажчик на рядок (mode), який має вказівку на засіб (режим) відкриття файлу. Функція повертає покажчик на тип FILE; це тип структури, визначеної в stdio.h. Потрібно пам’ятати, що покажчик, який повертає функція fopen() (місце розташування файлового буферу), повинен бути типу FILE.

Приклад виклику функції fopen();

FILE *FileOpend;

pFileOpend = fopen(FileName, “r”);

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

Режими доступу до файлу:

Режими

Призначення

r

Доступ тільки для читання. При відсутності вказаного файлу fopen() повертає нульовий покажчик (NULL).

w

Доступ тільки для запису. При відсутності вказаного файлу fopen() створює файл з таким ім’ям. Якщо файл з таким ім’ям існує, його вміст стирається.

a

Режим добавлення даних. Якщо файл з вказаним ім’ям не існує, fopen() створює його. В існуючий файл дані додаються до уже створених раніше.

r+

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

w+

Режим для читання і запису. Якщо файл з вказаним ім’ям не існує, fopen() створює його. Якщо файл з таким ім’ям існує, колишній вміст файла стирається.

a+

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


Таблиця містить опис варіантів відкриття файлів тільки в текстових режимах; для відкриття файла в двійковому режимі необхідно до приведених в таблиці описів відповідного режиму добавити символ b.

Наприклад, приведений нижче фрагмент коду С запитує у користувача ім’я файлу, потім намагається відкрити його в режимі тільки для читання в двійковій формі:

FILE *pDiskFile;

puts(“введіть ім’я файлу, який читають”);

gets(EnterredFilename);

pDiskFile = fopen(EnterredFilename, “rb”);

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


Введення і виведення даних з файла.

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


- прямий;

- символьний;

- форматний, що аналогічно функціям форматного, рядкового і символьного введення-виведення.


Пряме введення-виведення.

При використанні цього засобу читання або запис в файл відбувається байтовими блоками визначеного розміру. Згаданий блок повинен десь знаходитись в пам’яті; для визначення його положення використовується покажчик типу void.

Зверніть увагу на використання операції sizeof; це кращий засіб гарантувати, що прочитаєте необхідну кількість байтів. Якщо згадати, що ім’я масиву або структури є константним покажчиком; таким чином, використовувати ім’я структури в якості покажчика місця, куди повинна бути записана структура.

Приведемо приклад функції, яка зчитує дані з відкритого файлу в масив структур. Функція використовує деякі ще не розглядані оператори; найбільш важливим з яких є виклик функції fread() і супровідні йому операції. Звернемо увагу, що ця функція звертається до функції FileExists() для перевірки існування файлу; при відсутності файлу виводиться повідомлення про помилку і відбувається вихід із функції без читання даних:

int FileLoad(char *FileName,

struct NameRecord *pNames)

{

FILE *pDickFile;

Int counter = 1;

If((pDiskFile = FileExists(FileName) == NULL))

{

puts(“File Does Not Exist”);

return 0;

}

else

{

pDiskFile = fopen(FileName,”r”);

while(!feof(pDiskName))

{

fread(&pNames[counter++],

sizeof(struct NameRecord),

1, pDiskFile);

}

fclose(pDiskFile);

}

return counter – 1;

}


Символьне введення-виведення.

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

int fgetc(FILE *file_pointer);

int fputc(FILE *file_pointer);

char *fgets(char *buffer, int numch, FILE *fpointer);

char *fputs(const char *str, FILE file_pointer);

Функція fgetc() повертає значення одного символу з файла, на який поставлений покажчик; putc() записує в файл один символ. Функції fgets() i fputs() використовуються для роботи з цілими рядками.


Форматне введення-виведення.

Також існують функції введення-виведення файлового потоку, які є аналогами функцій scanf() i printf(). Це функції fscanf() i fprintf(). Їх прототипи:

int fprintf(FILE *file_pointer,

const char *format…);


int fscanf(FILE *file_pointer, const char *format…);


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

  • fread()призначена для прямого читання даних з відкритого файла; її прототип:

int fread(void *buffer, int blocksize, int blocks, FILE *fptr);

Передача функції покажчика (buffer) використовується для визначення в пам’яті місця зберігання даних; це може бути покажчик на змінну типу структура або на рядок. Крім того, функції треба передати розмір в байтах (blocksize) считуемого блока даних і кількість блоків (bloks), яке вона повинна повернути. Функції також потрібен покажчик на відкритий файл (fprt); це значення покажчика повертається функцією fopen(). Сама функція fread() повертає кількість прочитаних блоків.

Приклад для читання одного блоку даних із файла в структуру з іменем Name; ім’я структури – Namedef:

fread(&Name, sizeof(struct Namedef), 1, pFilePointer);

  • функція fwrite()


призначена для запису даних в відкритий файл.

Її прототип зберігається в файлі stdio.h, має вигляд:

int fwrite(void *buffer, int blocksize,

int blocks, FILE *fprt);

Ця функція виконує записування даних із області пам’яті, визначеної покажчиком buffer. Вона записує необхідну кількість (blocks) блоків заданого розміру (blocksize) в байтах в відкритий файл, який визначає покажчик fprt. Функція повертає кількість записаних блоків. Оператор для запису даних із структури з іменем Name в файл, визначений покажчиком pFilePointer буде мати такий вигляд:

fwrite(&Name, sizeof(sttruct NameDef), 1,

pFilePointer);

  • функція fclose()

закриває файл і зв’язаний з ним потік даних.

Її прототип:

int fclose(FILE *file_pointer);

При успішному закриттю потоку, функція повертає нуль, в випадку помилки повертає -1. file_pointer є значення, повертаєме при першому виклику функції fopen() для підготовки файла до роботи. Таким чином оператор закриття файлу має вигляд:

fclose(pFilePointer);

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

  • Якщо ви бажаєте повернути індикатор позиції в початкове положення скористайтесь функцією rewind(). Вона викликається таким чином:

rewind(pFilePointer);

і дозволяє встановити індикатор позиції на початок файлу.

  • І остання функція в цьому розділі це функція fseek().

Її прототип:

int fseek(FILE *file_pointer, long offset,

int origin);

Ця функція виконує зміну на величину offset значення індикатора позиції файла, на який вказує file_pointer. Значення origin визначає початкове положення, відносно якого буде проводитись зміщення. Нульове значення цієї величини відповідає початку файла; при значені рівному 1, відлік буде вестись від поточної позиції в файлі; при значенні, рівному 2, відлік буде вестись від кінця файлу. Зміщення позиції буде виконано на кількість байтів, визначаємих значенням offset. Таким чином, щоб встановити позицію, що відстоїть на два записи від кінця файлу, потрібно викликати функцію з такими параметрами:

fseek(pFilePointer, 2*(sizeof(struct Record),2));

Існує ще декілька операцій з файлами про які ви повинні мати уявлення. Кожна з цих операцій – переіменування і вилучення файлів – має еквівалент серед команд операційної системи. Часто буває доречно перекласти таку роботу на саму операційну систему, щоб не завдавати собі зайвий клопіт, якщо помилково будуть вилучені потрібні файли.

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


Функція С rename() змінює ім’я існуючого файла даних.

Її прототип:

int rename(const char *old_name,

const char *new_name);

Якщо старе ім’я Old_Name, а нове New_Name, то переіменування виконано успішно, і -1 в іншому випадку. Збій при виконанні функції може бути зв’язаний з тим, що в дійсності старого імені не існує. Те ж саме відбудеться, якщо файл з новим іменем уже існує або ви спробуєте вийти за межі диску (Приклад, спробуйте перейменувати файл на диску С в файл на диску А, оскільки така операція уже буде не переіменуванням, а переміщенням файла).


Іноді файл потрібно вилучити.

Функція С remove() призначена для вилучення файла. Це найнебезпечніша із всіх функцій. Її прототип має вигляд:

remove(Filename);

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

Найди помилку.

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

void DeleteFile(char *FileName)

{

char choise;

puts(“Дійсно ви хочете вилучити файл?”);

choise = getch();

remove(FileName);

if(choise == ‘y’)

puts(“Файл вилучено”);

return;

}

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

void DeleteFile(char *FileName)

{

char choise;

puts(“Дійсно ви хочете вилучити файл?”);

choise = getch();

if(choise == ‘y’)

{

remove(FileName);

puts(“Файл вилучено”);

return;

}

else

{

puts(“Файл не вилучено”);

return;

};


Питання до самоконтролю.

  1. Що таке файловий буфер? Як зв’язаний буфер з потоком даних?

  2. Назвіть фукцію для підготовки файла до роботи. Що повертає ця функція?

  3. Вкажіть різницю між двійковими і текстовими режимами доступу до файла.

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

  5. Вкажіть різницю між послідовним і довільним доступом до файлу. Поясніть призначення покажчика позиції в цій схемі. Яка функція використовується для встановлення індикатора позиції в задане місце в файлі?

  6. Що таке логічний (фізичний) файл?

  7. Поясніть правила введення із файла рядкових і дійсних даних.

  8. Поясніть правила форматного виведення даних символьного, рядкового і дійсного типів.

  9. Що таке бінарний файл?

  10. Як оголосити бінарний файл?

  11. Які типи даних можливо зберігати в бінарному файлі?

  12. Яка функція використовується для зв’язку бінарного логічного файла програми з фізичним файлом?

  13. Які функції використовуються для обміну між ОП і бінарним файлом?

  14. Поясніть призначення, параметри і повертаєме значення для функцій роботи з бінарними файлами: fopen, fread, fwrite, feof, fseek, rewind, remove.

  15. Поясніть процес обробки даних в вашій лабораторній роботі.

8