images.jpg

 

 

Попередня сторінка          Зміст           Наступна сторінка          Електронні посібники ВНТУ

 

 

 

ЛАБОРАТОРНА РОБОТА № 8

РОБОТА З ФАЙЛАМИ

images (4)
 

 

Мета роботи

  •  Вивчити програмні засоби для роботи з файлами та потоками.
  •  Дослідити основні функції роботи з файлами та реалізовувати найпростіші операції з ними.
  •  Навчитись застосовувати у своїх програмах вхідні і вихідні текстові і бінарні файли і файлові потоки.

 

 

 
 images (47).jpg
        

       ТЕОРЕТИЧНІ ВІДОМОСТІ

 

 

 

Поняття файлів і потоків

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

Текстовий потік – це послідовність символів. У стандарті С вража­ється, що текстовий потік організований у вигляді рядків, кожен з яких за­кін­чується символом нового рядка. Проте, в кінці останнього рядка цей символ не є обов'язковим. В текстовому потоці на вимогу базового середовища можуть відбуватися певні перетворення символів. Тому може і не бути однозначної відповідності між символами, які пишуться (читають­ся), і тими, які зберігаються в зовнішньому пристрої. Крім того, кількість тих символів, які пишуться (читаються), і тих, які зберігаються в зовні­ньому пристрої, може також не співпадати із-за можливих перетворень.

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

 

Файли і функції файлової системи у мові  С

У мові С файлом може бути все що завгодно, починаючи з дискового файлу і закінчуючи терміналом або принтером. Потік пов'язують з певним файлом, виконуючи операцію відкриття.

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

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

У кожного потоку, пов'язаного з файлом, є керуюча структура, яка містить інформацію про файл, вона має тип 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 і FILEsize_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 пов'язаний з клавіатурою, а coutcerr – з дисплеєм.

Файл <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;
      }

 

images (37).jpg

 

Порядок виконання роботи

 

 

  1. Ознайомитись з теоретичним матеріалом, з функціями стандартних бібліотек для роботи файлами і файловими потоками.
  2. Дослідити процес реалізації завдань прикладів, відлагодити наведені програму на своєму комп’ютері.
  3. Розробити власні програми, які реалізує індивідуальне завдання.
  4. Підготувати звіт по кожній задачі:
    •   варіант і текст завдання;
    •   лістинг програми;
    •   схему даних (для обох задач) і схему взаємозв’язку функцій (лише для другоі задачі);
    •   роздруківку вхідних і вихідних файлів і результати виконання;
    •   висновки.

 

 

images (60).jpg

 

Варіанти індивідуальних завдань

 

Задача 1. Взявши за основу лабораторну роботу №5, змінити код програми таким чином, щоб:

–  вхідні дані вводилися не з клавіатури, а з файлу,

–  результати виконання виводились і на екран, і у файл.

Задача 2. Взявши за основу лабораторну роботу №7(задача 1), змінити код програми таким чином, щоб:

–  вхідні дані (поля структури) вводилися з клавіатури і після введення записувалися у файл (окрема функція);

–  програма мала можливість дописувати  дані у файл (окрема функція);

–  дані з файлу виводились на екран (окрема функція);

–  результати виконання другого підпункту виводились на екран і у файл.

При цьому виконати завдання задачі №2 у двох варіантах:

1)  за допомогою класів потоків ofstream  та  ifstream;

2)  за допомогою структури FILE та функцій роботи з нею.

 

Задача 4. Одним за найпростіших в реалізації та найшвидших методів шиф­рування є накладання гами – послідовності псевдовипадкових чисел – шляхом виконання операції побітового додавання за модулем 2 (також відомої як exclusive or чи скорочено XOR).

Розробіть програму для зашифрування та розшифрування файлів з довіль­ним розширенням, використовуючи як ключ, на основі якого генерується послідовність псевдовипадкових чисел, номер варіанту.

 

ask5-1

 

Контрольні питання

 
  1. Дати поняття потоків і файлів. Який між ними зв’язок?
  2. Які види потоків бувають? Пояснити різницю між ними.
  3. Охарактеризувати стандартні потоки введення-виведення.
  4. Яким чином можна оголосити і відкрити файл?
  5. Шо таке режими відкриття файлів і які режими ви знаєте?
  6. Наведіть приклади форматованого запису у файл і читання з нього.
  7. Яким чином можна встановлювати покажчик файлу у задану позицію?
  8. Яким чином можна здійснювати запис і зчитування блоками?
  9. Чи можна одночасно використовувати файл для запису і читання?
  10. Що таке файлові потоки? Які поняття програмування забезпечують роботу з ними? Назвіть їх.
  11. Основні функції роботи з файловими потоками.
  12. Які режими доступу до файлових потоків ви знаєте?
  13. Яким чином можна виводити у файлові потоки і вводити великі обсяги даних (структури, масиви)?
  14. Як можна перевірити, чи закінчився файл, і наявність помилок?
  15. Наведіть приклади запису і читання по символах, по словах, по рядках та блоками довільного розміру.