Перевизначення файлів та потоків

Мета роботи.Вивчити принципи і методи перевизначення дескрипторів файлів і покажчиків на потоки.

Теоретична частина.

Програміст може забезпечити обмін інформацією із зовнішніми пристроями шляхом використання системи введення-виведення нижнього рівня. На відміну від потоків ця система не передбачає буферизацію даних і не виконує форматне введення і виведення.

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

Одним із засобів для відкриття файлів є функція

int open (char *pathname, int oflag[, int pmode]).

Функція відкриває файл, визначений в pathname, і готує файл для читання або запису згідно режиму, що визначений в oflag. Аргумент oflag є цілим виразом сформованим комбінацією однієї або більш констант. Аргумент pmode потрібен тільки тоді, коли створюється новий файл і визначає спосіб доступу до файлу, що встановлюється при першому закритті файлу. Pmode є цілий константний вираз. Константи, що використовуються у функції open, визначені у заголовочному файлі fcntl.h. і детально описані в лабораторній роботі "Файли з довільною вибіркою".

Функція повертає номер для відкритого файлу. Повернення -1 повідомляє про помилку.

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

Для примусового закриття файлу з handle можна використати функцію

int close(int handle).

Функція повертає 0, якщо файл успішно був закритий і -1 - у протилежному випадку.

На початку виконання кожній Сі-програми в системній таблиці файлів автоматично виділяються перші 5 рядків, що відповідають таким логічним пристроям як стандартному введенню (хендл равен 0), виведенню (1), помилкам (2), послідовному обміну (3) і стандартному друку (4):

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

Приклад.

#include <fcntl.h>

#include <types.h>

#include <stat.h>

#include <io.h>

main( )

{

int e;

close(2);

if(-1==(e=open("file.err",O_WRONLY|O_CREAT|O_APPEND,S_IWRITE)))

реrror("Спроба відкрити файл невдала");

}

В даному прикладі після виконання функції close звільняється другий рядок в таблиці файлів, що відповідає виведенню помилок. Далі створюється доступний для запису файл file.err. Цей файл відкривається для додавання. Його хендл рівний 2. Якщо спроба відкриття буде невдала, то функція реrror виводить повідомлення про помилки у файл file.err.

Функції dup і dup2 дозволяють Вам призначати багато хендлів для одного файлу одночасно, а також один і той же хендл послідовно пов'язувати з різними файлами та пристроями.

Функція

int dup( int handle)

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

Приклад

int fh,q;

fh=open("data",O_WRONLY|O_CREAT|O_APPEND,S_IWRITE);

q=dup(fh);

До файлу "data" можна звертатися використовуючи хендл fh або q.

Функція

int dup2(int handle1, int handle2)

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

При успішному завершенні функція dup2 повертає 0.

Приклад

#include <stdio.h>

#include <io.h>

#include <fcntl.h>

#include <stat.h>

main()

{int e;

e=open("file.out",O_WRONLY|O_CREAT|O_APPEND,S_IWRITE);

dup2(e,1);

printf("Виведення\n");

}

Стандартне виведення перепризначено у файл file.out. В цей файл буде виведений рядок "Виведення".

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

Обидві функції повертають -1, якщо відбулася помилка. При цьому код помилки errno встановлюється в одне з наступних значень:

EBADE - недійсний файл handle

EMFILE - немає більше доступних handle (дуже багато відкритих файлів).

Функції dup-dup2 застосовуються, як правило, для перепризнячення стандартних зовнішніх логічних пристроїв на різні фізичні пристрої і дискові файли.

Так само, як при роботі з базовою системою введення-виведення, можете перевизначати і потоки. (Детально потоки описані в лабораторній роботі №2.)

Коли програма починає виконуватися, автоматично відкриваються 5 потоків, відповідних першим п'яти рядкам системної таблиці файлів. Це такі потоки: стандартне введення, стандартне виведення, стандартні помилки, стандартний послідовний порт і стандартний друк. За умовчанням, стандартне введення-виведення і стандартні помилки - це консоль.

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

Коли Ви використовуєте функції введення-виведення для стандартних потоків, Ви можете використовувати як вказівники на потік наступні константи: stdin ( стандартне введення ), stdout ( стандартне виведення ), stderr( помилки ), stdaux(послідовний порт), stdprn ( стандартний друк). Наприклад, функція fputc('*', stdout) виведе символ '*' в стандартний вихідний потік.

Ви можете перевизначити stdin, stdout, stderr, stdaux або stdprn так, що вони відноситимуться до файлу на диску або пристрою. Для цього використовують функцію

FILE *freopen(char *pathname,char *type, FILE *stream);

Функція закриває файл або пристрій, пов'язаний з потоком stream, і перепризначає потік stream на файл, визначений в pathname. Новий файл, пов'язаний з потоком stream, відкривається із заданим типом доступу type. Повний опис можливих типів доступу наведено в лабораторній роботі "Прямий доступ в потоках". Тут ми обмежимося тільки трьома:

"r" - відкрити для читання (файл повинен існувати);

"w" - відкрити порожній файл для запису, якщо файл існує, то його вміст втрачається;

"a" - відкрити для запису в кінець файлу (додавання); файл створюється, якщо він не існує;

Функція повертає покажчик на новий відкритий файл і NULL при помилці.

Наприклад, після оператора

FILE * stream = freopen ("data2","а",stdout);

стандартний потік виведення перепризначується з екрану дисплея у файл data2, відкритий в режимі додавання.

Практична частина.

1. Вивчити засоби перевизначення файлів і потоків, викладені в теоретичній частині. Вміти відповідати на контрольні питання, наведені нижче.

2. Написати програму, яка виконує наступні дії по перевизначенню хендлів

а) Відкрити файл в режимі додавання

open("data",O_WRONLY|O_CREAT|O_APPEND,S_IWRITE)

зв'язавши його з хендлом N 4; спробувати в цьому пункті обійтися без функцій dup і dup2;

б) Перепризначивши хендли, вивести рядок, що містить версію операційної системи, у файл data;

в) Перепризначивши хендли, вивести версію операційної системи на екран;

г) Повторити пункти б) і в) в циклі 5 разів. Як на екрані так і у файлі повинні бути 5 рядків, що містять інформацію про версію операційної системи.

3. Скласти програму, що виконує наступні дії при перевизначенні потоків:

а) Призначити стандартне виведення в потік, пов'язаний з файлом, відкритим в режимі додавання;

б) Використовуючи функцію puts(char*), вивести рядок в стандартний потік виведення;

в) Перепризначити виведення на екран, консоль має ім'я "con";

г) Повторити пункти а), б) і в) в циклі 5 разів. Як на екрані, так і у файлі повинні бути 5 виведених рядків.

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

1. Чим відрізняється введення-виведення нижнього рівня від обміну інформацією за допомогою потоків?

2. Що таке дескриптор файлу і де він розташований?

3. Що таке хендл і як він використовується в програмах?

5. Як відкрити файл і які дії при цьому відбуваються в системі?

7. Скільки зайнято рядків в системній таблиці файлів на початку роботи програми і що в них записано?

8. Чи можна одночасно пов'язати декілька файлів з одним хендлом?

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

10. Якарізниця між функціями dup та dup2і що між ними спільного?

11. Коли функцію dup2 можна замінити послідовністю викликів close і dup?

12. Яка стратегія виділення функцією dup копії дескриптора?

13. Як провести перевизначення потоків?

14. Які дії виконує функція freopen?

Лабораторна робота №5.

Наши рекомендации