Лекція № 8
Тема: Файли. Робота з файлами.
План
Загальні поняття про потік
Відкриття та закриття потоку
Функції для роботи з файлами
Двійковий режим обміну з файлами
Загальні поняття про потік
На рівні потокового вводу/виводу обмін даними виконується побайтно. Для файлів на диску за одне звертання до пристрою виконується читання або запис фіксованої порції даних. Частіше всього мінімальною порцією даних, що бере участь в обміні з зовнішньою пам'яттю, є блоки в 512 байт або 1024 байти. При введенні з диска (при читанні з файлу) дані поміщаються в буфер операційної системи, а потім побайтно або визначеними порціями передаються програмі користувача. При виведенні даних у файл вони нагромаджуються в буфері, а при заповненні буфера записуються у вигляді єдиного блоку на диск за одне звернення до нього. Буфери операційної системи реалізуються у вигляді ділянок основної пам'яті. Тому пересилання між буферами введення-виведення виконуваною програмою відбуваються достатньо швидко на відміну від реальних обмінів з фізичними пристроями. Таким чином, потік - це файл разом із засобами буферизації, які надаються.
При роботі з потоком можна проводити наступні дії:
• відкривати і закривати потоки (зв'язувати покажчики на потоки з конкретними файлами);
• вводити і виводити: символ, рядок, форматовані дані, порцією даних довільної довжини;
• аналізувати помилки потокового введення-виведення і умову досягнення кінця потоку (кінця файлу);
• управляти буферизацією потоку і розміром буфера;
• одержувати і встановлювати покажчик (індикатор) поточної позиції в потоці.
Для того, щоб можна було використовувати функції бібліотеки введення-виведення мови Сі, в програму необхідно включити файл stdio.h (#include <stdio.h>), який містить прототипи функцій введення-виведення, а також визначення констант, типів і структур, необхідних для роботи функцій обміну з потоком.
Відкриття і закриття потоку
Перш ніж почати працювати з потоком, його необхідно ініціалізувати, тобто відкрити. При цьому потік зв'язується в виконуваній програмі із структурою наперед визначеного типу FILE. Визначення структурного типу FILE знаходиться в файлі stdio.h. В структурі FILE містяться компоненти, за допомогою яких ведеться робота з потоком, зокрема: покажчик на буфер, покажчик (індикатор) поточної позиції в потоці і інша інформація. При відкритті потоку в програму повертається покажчик на потік, який є покажчиком на об'єкт структурного типу FILE. Цей покажчик ідентифікує потік в усіх наступних операціях.
Покажчик на потік, наприклад fp, повинен бути оголошений в програмі таким чином:
#include <stdio.h>
FILE *fp;
Покажчик на потік набуває значення в результаті виконання функції відкриття потоку:
fp = fopen (ім'я_файлу, режим_відкриття);
Параметри ім'я_файлу і режим_відкриття є покажчиками на масиви символів, які містять відповідно ім'я файлу, пов'язаного з потоком, і рядок режимів відкриття. Однак ці параметри можуть задаватися і безпосередньо у вигляді рядків при виклику функції відкриття файлу:
fp = fopen("t.txt", "r");
де t. txt - ім'я деякого файлу, пов'язаного з потоком;
r - позначення одного з режимів роботи з файлом (тип доступу до потоку).
Стандартно файл, пов'язаний з потоком, можна відкрити в одному з наступних шести режимів:
"w" - новий текстовий файл відкривається для запису. Якщо файл вже існував, то попередній вміст стирається, файл створюється наново;
"r" - існуючий текстовий файл відкривається тільки для читання;
"а" -текстовий файл відкривається (або створюється, якщо файлу немає) для додавання в нього нової порції інформації (додавання в кінець файлу). На відміну від режиму "w" режим "а" дозволяє відкривати вже існуючий файл, не знищуючи його попередньої версії, і писати в продовження файлу;
"w+" - новий текстовий файл відкривається для запису і подальших багатократних виправлень. Якщо файл вже існує, то попередній вміст стирається. Подальші після відкриття файлу запис і читання з нього допустимі в будь-якому місці файлу, у тому числі запис дозволений і в кінець файла, тобто файл може збільшуватися;
"r+" - існуючий текстовий файл відкривається як для читання, так і для запису в будь-якому місці файлу; однак в цьому режимі неможливий запис в кінець файлу, тобто неприпустимо збільшення розмірів файла;
"а+" -текстовий файл відкривається або створюється (якщо файлу немає) і стає доступним для змін, тобто для запису і для читання в будь-якому місці; при цьому на відміну від режиму "w+" можна відкрити існуючий файл і не знищувати його вмістимого; на відміну від режиму "г+" в режимі "а+" можна вести запис в кінець файлу, тобто збільшувати його розміри.
Потік можна відкрити в текстовому або двійковому (бінарному) режимі.
В текстовому режимі прочитана з потоку комбінація символів CR (значення 13) і LF (значення 10), тобто управляючі коди "повернення
каретки" і "перевід рядка", перетворюються в один символ нового рядка '\n' (значення 10, співпадаюче з LF). При записі в потік в текстовому режимі здійснюється зворотне перетворення, тобто символ нового рядка '\n' (LF) замінюється послідовністю CR і LF.
Якщо файл, пов'язаний з потоком, зберігає не текстову, а довільну двійкову інформацію, то вказані перетворення не потрібні і можуть бути навіть шкідливими. Обмін без такого перетворення виконується при виборі двійкового або бінарного режиму який позначається буквою b. Наприклад, "r+b" або "wb". В деяких компіляторах текстовий режим обміну позначається буквою t, тобто записують "a+t" або "rt".
Якщо потік відкритий для змін, тобто в параметрі режиму присутній символ "+", то дозволено як введення в потік, так і читання з нього. Проте зміна режиму (перехід від запису до читання і назад) повинна відбуватися тільки після установки покажчика потоку в потрібну позицію.
Відкриті на диску файли після закінчення роботи з ними рекомендується закрити явно. Для цього використовується бібліотечна функція
int fclose (покажчик_на_поток);
Відкритий файл можна відкрити повторно (наприклад, для змінення режиму роботи з ним) тільки після того, як файл буде закритий за допомогою функції fclose().
Функції для роботи з файлами
В мові Сі можливо організовувати роботу з файлами на диску. Для цієї мети в бібліотеці мови Сі включені наступні функції:
fgetc(), getc() – ввід (читання) одного символу з файлу;
fputs(), putc() – запис одного символу в файл;
fprintf() – форматований вивід в файл;
fscanf() – фор матований ввід (читання) з файлу;
fgets( ) - введення (читання) рядка з файлу;
fputs( ) - запис рядка у файл.
Двійковий (бінарний) режим обміну з файлами.
Двійковий режим обміну організовується за допомогою функцій getc() і putc(), звернення до яких має наступний формат:
с= getc(fp);
putc(c, fp);
де fp - покажчик на потік;
c — змінна типу int для прийому чергового символу з файлу або для запису її значення у файл. Прототипи функції:
int getc ( FILE *stream);
int putc (int с, FILE * stream);
Як приклад використання функцій getc( ) і putc() розглянемо програми введення даних у файл з клавіатури і програму виведення їх на екран дисплея з файлу. Програма введення читає символи з клавіатури і записує їх у файл. Ознакою завершення введення служить поступивший від клавіатури символ '#'. Ім'я файлу запрошується у користувача. Якщо при введенні послідовності символів натискається клавіша <Enter>, яка служить роздільником рядків при введенні з клавіатури, то у файл записуються управляючі коди "Повернення каретки" (CR - значення 13) і "Переклад рядка" (LF — значення 10). Код CR при виведенні викликає перевід маркера (курсора) в початок рядка екрану дисплея. Код LF служить для переводу маркера на новий рядок дисплея. Значення цих кодів в тексті програми позначені відповідно ідентифікаторами CR і LF, тобто CR і LF - іменовані константи. Запис управляючих кодів CR і LF у файл дозволяє при подальшому виведенні файлу на екран відділити рядки один від одного.

/* Програма введення символів */
#include <stdio.h>
int main () FILE
*fp; /* Покажчик на потік */
char с;
/* Восьмирічний код "Повернення каретки": */
const char CR='\015';
/* Восьмерічний код "Переклад рядка": */
const char LF = '\012'/
char fname[20]; /* Масив для імені файлу */
/* Запит імені файлу: */
puts("введіть ім'я файлу: \n");
gets(fname)
/* Відкрити файл для запису: */
if ((fp = fopen(fname,"w")) == NULL)
{
реrror(fname);
return 1;
}
/* Цикл введення і запису у файл символів: */
while ((c = getchar()) != '#')
{
if (c == '\n')
{
putc(CR, fp);
putc(LF, fp);
}
else putc(с, fp);
}
/* Цикл введення завершений; закрити файл: */
fclose(fp);
return 0;
}
Наступна програма читає потік символів з раніше створеного файлу і виводить його на екран дисплея:
/* Програма виведення символьного файлу на екран дисплея */
#include <stdio.h>
int main ()
{
FILE *fp; /* Покажчик на потік */
char с;
char fname[20]; /* Масив для імені файлу */
/* Запит імені файлу: */
puts("введіть ім'я файлу: \n ")
gets(fname);
/* Відкрити файл для читання: */
if ((fp = fopen(fname,"r")) = = NULL)
{
реrror(fname);
return 1;
}
/* Цикл читання з файлу і висновку символів на екран: */
while ((с = getc(fp)) != EOF)
putchar(с);
fclose(fp);
/* Закрити файл */
return 0
}