Попередня сторінка Зміст Наступна сторінка Електронні посібники ВНТУ
ЛАБОРАТОРНА РОБОТА № 8
РОБОТА З ФАЙЛАМИ
Мета роботи
- Вивчити програмні засоби для роботи з файлами та потоками.
- Дослідити основні функції роботи з файлами та реалізовувати найпростіші операції з ними.
- Навчитись застосовувати у своїх програмах вхідні і вихідні текстові і бінарні файли і файлові потоки.
ТЕОРЕТИЧНІ ВІДОМОСТІ
Поняття файлів і потоків
В комп’ютерній системі між програмою і пристроєм знаходиться щось більш загальне, ніж сам пристрій. Такий узагальнений пристрій введення або виведення (пристрій більш високого рівня абстракції) називається потоком, в той час як конкретний пристрій називається файлом (файл – теж поняття абстрактне). Потоки бувають двох видів: текстові і двійкові.
Текстовий потік – це послідовність символів. У стандарті С вражається, що текстовий потік організований у вигляді рядків, кожен з яких закінчується символом нового рядка. Проте, в кінці останнього рядка цей символ не є обов'язковим. В текстовому потоці на вимогу базового середовища можуть відбуватися певні перетворення символів. Тому може і не бути однозначної відповідності між символами, які пишуться (читаються), і тими, які зберігаються в зовнішньому пристрої. Крім того, кількість тих символів, які пишуться (читаються), і тих, які зберігаються в зовніньому пристрої, може також не співпадати із-за можливих перетворень.
Двійковий потік – це послідовність байтів, яка взаємно однозначно відповідає байтам на зовнішньому пристрої, причому ніякого перетворення символів не відбувається. Крім того, кількість тих байтів, які пишуться (читаються), і тих, які зберігаються на зовнішньому пристрої, однакова. Однак наприкінці двійкового потоку може додаватися визначена додатком кількість нульових байтів (наприклад, для заповнення сектора на диску).
Файли і функції файлової системи у мові С
У мові С файлом може бути все що завгодно, починаючи з дискового файлу і закінчуючи терміналом або принтером. Потік пов'язують з певним файлом, виконуючи операцію відкриття.
Як тільки файл відкритий, можна проводити обмін інформацією між ним і програмою. При відкритті файлу покажчик поточної позиції у файлі встановлюється в початок. При читанні з файлу (або записі в нього) кожного символу покажчик поточної позиції збільшується, забезпечуючи просування по файлу.
Файл від'єднується від певного потоку (тобто розривається зв'язок між файлом і потоком) за допомогою операції закриття.
У кожного потоку, пов'язаного з файлом, є керуюча структура, яка містить інформацію про файл, вона має тип FILE. У цьому блоці управління файлом ніколи нічого міняти не можна.
Для роботи з файловою системою існує заголовочний файл <stdio.h>. Часто використовувані функції файлової системи С такі (табл. 8.1 ).
Таблиця 8.1 – Функції для роботи з файловою системою
Назва | Що робить |
---|---|
fopen() | Відкриває файл |
fclose() | Закриває файл |
putc() | Записує символ у файл |
fputc() | Те саме, що і putc() |
getc() | Читає символ з файлу |
fgetc() | Те саме, що і getc() |
fgets() | Читає рядок з файлу |
fputs() | Записує рядок у файл |
fseek() | Встановлює покажчик поточної позиції на певний байт файлу |
ftell() | Повертає поточне значення покажчина у файлі |
fprintf() | Для файлу те саме, що printf() для консолі |
fscanf() | Для файлу те саме, що scanf() для консолі |
feof() | Повертає значення true (істина), якщо досягнуто кінець файлу |
error() | Повертає значення true, якщо виникла помилка |
rewind() | Встановлює покажчик поточної позиції на початок файлу |
remove() | Знищуєт файл |
fflush() | Дозапис потоку у файл |
Заголовок <stdio.h> надає прототипи функцій введення/виведення і визначає наступні три типи: size_t, fpos_t і FILE. size_t і fpos_t представляють собою певні різновиди такого типу, як ціле без знака. А про третій тип, FILE, розповідається в наступному розділі.
Крім того, в <stdio.h> визначається декілька макросів. Серед них:
NULL, EOF, FOPEN_MAX, SEEK_SET, SEEK_CUR і SEEK_END.
Макрос NULL визначає порожній (null) покажчик. Макрос EOF часто визначається як -1, і є значенням, що повертається тоді, коли функція введення намагається виконати читання після кінця файлу. FOPEN_MAX – ціле значення, рівне максимальному числу одночасно відкритих файлів. Інші макроси вико ристовуються разом з fseek(), що виконує операції прямого доступу до файлу.
Щоб оголосити змінну-покажчик файлу, пишуть:
FILE *fp;
Функція fopen() відкриває потік і пов'язує з цим потоком певний файл. Потім вона повертає покажчик цього файлу:
FILE *fopen (const char *ім'я_файлу,const char *режим);
Рядок "режим", визначає, яким чином файл буде відкритий. Рядки, подібні "r+b" можуть бути представлені і у вигляді "rb+" (табл. 8.2).
Таблия 8.2 – Режими відкриття файлів
Режим | Що означає |
---|---|
r | Відкрити текстовий файл для читення |
w | Створити текстовий файл для запису |
a | Додати в кінець текстового файлу. Якщо файл не існує, то він буде створений. Всі нові дані, які записуються в нього, будуть додаватися в кінець файлу. |
rb | Відкрити двійковий файл для читання |
wb | Створити двійковий файл для запису |
ab | Додати в кінець двійкового файла |
r+ | Відкрити текстовий файл для читання/запису. Вміст залишиться недоторканим. Якщо файлу не існує, то він створений не буде. |
w+ | Створити текстовий файл для читання /запису. Якщо файл не існує, то він буде створений. Якщо файл вже існує, то відкриття призведе до втрати його вмісту, а в режимі r+ він залишиться недоторканим |
a+ | Додати в кінець текстового файлу або створити його для читання/запису |
r+b | Відкрити двійковий файл для читання /запису |
w+b | Створити двійковий файл для читання /запису |
a+b | Додати в кінець двійкового файла або створити його для читання /запису |
Робота з файловими потоками
У мові С++ введення/виведення описується як набір класів, описаний в заголовному файлі iostream.h. Аналогами потоків stdin, stdout, stderr є класи cin, cout і cerr. Ці три потоки відкриваються автоматично. Потік cin пов'язаний з клавіатурою, а cout, cerr – з дисплеєм.
Файл <fstream.h> визначає класи ifstream і ofstream, за допомогою яких програма може виконувати операції файлового введення/виведення. Для відкриття файлу на введення/виведення оголошують об'єкт типу ifstream/ ofstream, передаючи конструктору цього об'єкта ім'я необхідного файлу:
ofstream myOutput ("FileOut.EXT");
ifstream myInput ("FileIn.EXT");
Після того, як програма відкрила файл для введення або виведення, вона може читати або писати дані, використовуючи оператори: "<<" – для занесення (запису) в потік; ">>" – для вилучення (читання) з потоку.
char word [64];
while (!myInput.eof ())
{ myInput >> word; // зчитуэмо слово (до пробілу)
cout <<word <<endl; // виводимо на екран
myOutput << word; // записуємо у файл
}
Більшість програм читають вміст файлу, поки не зустрінеться кінець файлу. Визначити кінець файлу можна за допомогою функції eof().
Для введення або виведення символів у файл або з файлу використовую функції get() і put().
char letter;
while (!myInput.eof ())
{ letter = myInput.get(); // зчитуємо з файлу
cout <<letter; // виводимо на екран
myOutput.put(letter); // записуємо у файл
}
Для зчитування цілого рядка використовують функцію getline():
char line [80];
while (!myInput.eof ())
{ myInput.getline (line,sizeof (line));
cout <<line <<endl;
}
Для перевірки помилок можна використовувати функцію fail():
if (myInput.fail ())
{ cerr <<"Помилка відкриття FileIn.txt" <<endl;
exit (1);
}
Якщо програмам необхідно вводити або виводити такі дані, як структури або масиви, можна використовувати методи read() і write().
myInput.read (buffer, sizeof (buffer));
myOutput.write (buffer, sizeof (buffer));
Якщо програма завершила роботу з файлом, його слід закрити за допомогою функції close().
Для того, щоб операції введення/виведення виконувалися не з початку файлу, можна використовувати інші режими відкриття файлів (табл. 8.3).
Таблиця 8.3 – Режими відкриття файлових потоків
Режим відкриття | Призначення |
---|---|
ios::app | Відкриває файл в режимі додавання, встановлюючи файловий покажчик на кінець файлу |
ios::ate | Встановлює файловий покажчик на кінець файлу |
ios::in | Вказує відкрити файл для введення. |
ios::nocreate | Якщо й файл не існує, не створювати файл і повернути помилку |
ios::noreplace | Якщо файл існує, операція відкриття повинна бути перервана и повинна повернути помилку |
ios::out | Вказує відкрити файл для виведення. |
ios::trunc | Перезаписує вміст існуючого файлу |
ios::binary | Робота з файлом у двійковому вигляді |
Наприклад,
ifstream myFile ("Filename.txt", ios::out | ios::noreplace);
Для читання і запису даних будь-якого типу, тип яких може займати більше 1 байта, у файловій системі мови С є дві функції: fread() і fwrite().
size_t fread(void *buf,size_t count,size_t k,FILE *pf);
size_t fwrite(const void *buf,size_t count,size_t k,FILE *pf);
Функція fread() повертає кількість прочитаних елементів. Якщо досягнуто кінець файлу або сталася помилка, то повернуте значення може бути менше, ніж лічильник. А функція fwrite() повертає кількість записаних елементів. Якщо помилки не було, то повернений результат буде дорівнює значенню лічильник. Одним з найбільш корисних застосувань функцій fread() і fwrite() є читання і запис даних користувача типів. Наприклад, якщо визначена структура
struct struct_type {
float balance;
char name [80];
} Cust;то наступний оператор записує вміст Сust у файл, на який вказує fp:
fwrite (&cust, sizeof (struct struct_type), 1, fp);
В системі введення/виведення мови С є функції fprintf() і fscanf():
int fprintf (FILE * pf, const char *str, ...);
int fscanf (FILE * pf, const char *str, ...);
Приклади програм для робот из файлами
Приклад 1. Введення інформації з клавіатури і виведення на диск.
int main (int argc, char * argv [])
{
FILE * fp;
char ch;
if (argc! = 2)
{
printf ("Ви забули ввести ім'я файлу. \n");
exit (1);
}
if ((fp = fopen (argv [1], "w "))== NULL)
{
printf ("Помилка при відкритті файлу. \n");
exit (1);
}
do { ch = getchar ();
putc (ch, fp);
} while (ch! ='$');
fclose (fp);
return 0;
}
Приклад 2. Програма читає текстовий файл і виводить його на екран
int main (int argc, char * argv [])
{
FILE * fp;
char ch;
if (argc! = 2) {
printf ("Ви забули ввести ім'я файлу. \n");
exit (1);
}
if ((fp = fopen (argv [1], "r "))== NULL) {
printf ("Помилка при відкритті файлу. \n");
exit (1);
}
ch = getc (fp); /* читання одного символу */
while (ch! = EOF) {
putchar (ch); /* виведення на екран */
ch = getc (fp);
}
fclose (fp);
return 0;
}
Приклад 3. Програма вводить рядок з клавіатури, записує у файл, а потім читає файл і виводить його вміст на екран
int main (void)
{ char str[80];
FILE *fp;
if ((fp = fopen ("TEST", "w+"))== NULL) {
printf ("Помилка при відкритті файлу. \n");
exit (1);
}
do { printf("Введіть рядок (порожній – для виходу): \n");
gets(str);
strcat(str, "\n"); /* введення роздільник рядків */
fputs(str, fp);
} while(*str != '\n');
/* Тепер виконується читання і відображення файлу */
rewind(fp); /* встановити покажчик на початок файлу */
while (!feof(fp))
{ fgets (str,79,fp);
printf (str);
}
return 0;
}
Приклад 4. Використання форматованого введення-виведення у файл
int main (void)
{
FILE *fp;
char s[80];
int t;
if ((fp = fopen ("test", "w")) == NULL)
{ printf ("Помилка відкриття файлу. \n");
exit (1);
}
printf ("Введіть рядок і число:");
fscanf (stdin, "%s%d",s,&t); // читати з клавіатури
fprintf (fp, "%s%d",s,t); // писати в файл
fclose (fp);
if ((fp = fopen ("test", "r")) == NULL)
{ printf ("Помилка при відкритті файлу. \n");
exit (1);
}
fscanf (fp, "%s%d",s,&t); // читання з файлу
fprintf (stdout, "%s%d",s,t); // виведення на екран
return 0;
}
Порядок виконання роботи
- Ознайомитись з теоретичним матеріалом, з функціями стандартних бібліотек для роботи файлами і файловими потоками.
- Дослідити процес реалізації завдань прикладів, відлагодити наведені програму на своєму комп’ютері.
- Розробити власні програми, які реалізує індивідуальне завдання.
- Підготувати звіт по кожній задачі:
- варіант і текст завдання;
- лістинг програми;
- схему даних (для обох задач) і схему взаємозв’язку функцій (лише для другоі задачі);
- роздруківку вхідних і вихідних файлів і результати виконання;
- висновки.
Варіанти індивідуальних завдань
Задача 1. Взявши за основу лабораторну роботу №5, змінити код програми таким чином, щоб:
– вхідні дані вводилися не з клавіатури, а з файлу,
– результати виконання виводились і на екран, і у файл.
Задача 2. Взявши за основу лабораторну роботу №7(задача 1), змінити код програми таким чином, щоб:
– вхідні дані (поля структури) вводилися з клавіатури і після введення записувалися у файл (окрема функція);
– програма мала можливість дописувати дані у файл (окрема функція);
– дані з файлу виводились на екран (окрема функція);
– результати виконання другого підпункту виводились на екран і у файл.
При цьому виконати завдання задачі №2 у двох варіантах:
1) за допомогою класів потоків ofstream та ifstream;
2) за допомогою структури FILE та функцій роботи з нею.
* Задача 4. Одним за найпростіших в реалізації та найшвидших методів шифрування є накладання гами – послідовності псевдовипадкових чисел – шляхом виконання операції побітового додавання за модулем 2 (також відомої як exclusive or чи скорочено XOR).
Розробіть програму для зашифрування та розшифрування файлів з довільним розширенням, використовуючи як ключ, на основі якого генерується послідовність псевдовипадкових чисел, номер варіанту.
Контрольні питання
- Дати поняття потоків і файлів. Який між ними зв’язок?
- Які види потоків бувають? Пояснити різницю між ними.
- Охарактеризувати стандартні потоки введення-виведення.
- Яким чином можна оголосити і відкрити файл?
- Шо таке режими відкриття файлів і які режими ви знаєте?
- Наведіть приклади форматованого запису у файл і читання з нього.
- Яким чином можна встановлювати покажчик файлу у задану позицію?
- Яким чином можна здійснювати запис і зчитування блоками?
- Чи можна одночасно використовувати файл для запису і читання?
- Що таке файлові потоки? Які поняття програмування забезпечують роботу з ними? Назвіть їх.
- Основні функції роботи з файловими потоками.
- Які режими доступу до файлових потоків ви знаєте?
- Яким чином можна виводити у файлові потоки і вводити великі обсяги даних (структури, масиви)?
- Як можна перевірити, чи закінчився файл, і наявність помилок?
- Наведіть приклади запису і читання по символах, по словах, по рядках та блоками довільного розміру.