Мета роботи. Вивчити методи проектування файлів з прямим доступом.
Основною одиницею роботи операційних систем (ОС) є файл. При роботі з файлами ОС створює і коректує спеціальні області в пам'яті, що відображають поточний стан файлу. Такі області називають дескрипторами файлів.
Дескриптор створюється при відкритті файлу та містить таку інформацію про файл як його ім'я, накопичувач, розмір запису тощо. ОС створює дескриптор у вільній області пам'яті і привласнює їй унікальний номер - хендл. Далі при роботі використовується не ім'я файлу, а номер його дескриптора. У ряді операційних систем програма користувача працює з простором на диску, який займає файл, не безпосередньо, а через системні буфери. Це зроблено з метою збільшення швидкості обміну. Обмін з диском відбувається порціями даних розміром в один сектор.
При обміні з файлом повинна бути визначена область даних у програмі, в яку або з якої прямуватимуть дані. Цей простір в пам'яті може належати Вашій програмі, а може бути також розташований в системному або створеному Вами проміжному буфері обміну. В даній роботі використовується перший підхід.
Обмін програм з файлами проводиться одиницями інформації - логічними записами. Є два основні методи логічного доступу до файлу: послідовний і довільний. При послідовному доступі логічні записи зчитуються і записуются в строгій послідовності один за одним. При довільному доступі читання/запис може здійснюватися у довільний логічний запис, номер якого заздалегідь заданий.
При послідовному доступі найбільш часто в якості логічних записів розглядаються рядки: послідовності байт завершені символами '\r'(повернення каретки) і '\n' (перевод рядка), які мають десяткові коди 13 і 10, відповідно. В логічних записах зберігаються як числа, так і символи. Останні зберігаються по одному байту на символ і кодуються згідно прийнятій системі кодування. Числа зберігаються в символьному вигляді. Так ціле число 128, що займаює в пам'яті два байти (16-е представлення 00 80), розташовується у файлі в виді послідовності з трьох символів '1','2' і '8'. Найбільш характерним представником файлів з послідовним доступом є текстові файли, що використовуються для зберігання програм, документів і даних.
Оскільки всі записи в послідовному файлі мають довільну довжину, то для знаходження потрібного запису програма повинна прочитувати файл спочатку і відлічити потрібну кількість пар символів '\r' і '\n'.
Файли прямого доступу мають логічні записи фіксованої довжини. В цьому випадку легко можна працювати з логічною записом, що має довільний номер. Для цього треба просто обчислити номер байта у файлі, відповідний початковому байту шуканого запису і встановити на нього вказівник запису/зчитування. Кожний запис може містити декілька полів, що мають фіксований розмір. Наприклад, записи файлу, що містить інформацію про пацієнтів деякої лікарні, можуть містити наступні поля: Прізвище, Зріст, Вага, Рік народження тощо. Символи в записах зберігаються по одному байту, а числа зберігаються в тому ж вигляді, як вони представляються в пам'яті.Наприклад, число 128 зберігається у вигляді послідовності двох байт '\x00' і '\x80'. Файли прямого доступу створюються наперед і спочатку містять порожні записи, які заповнюються або змінюються по мірі необхідності. В найпростішому випадку розмір файлу з часом не змінюється.
ОС забезпечує прямий доступ до кожного байту файлу, тобто логічний запис складається з одного байта. Файл зберігається як логічно безперервна послідовність байт. Місце у файлі, з якого починатиметься наступна операція введення/ввиведення, називаєтся вказівником введення/виведення, який зберігається в дескрипторі файлу. Після кожної операції обміну положення вказівника змінюється. Вказівник програмно доступний, тобто можна прочитати його вміст і записати в нього нову позицію для наступної операції обміну. Забезпечення складнішого доступу до файлу покладається на програміста. Розглянемо функції введення-виведення низького рівня.
Функції введення/виведення нижнього рівня не виконують буферизацію і форматування, як це роблять функції обміну інформації з потоками типу fscanf і fprint. Низькорівневі функції можуть розглядатися як безпосереднє звернення до можливостей операційної системи. В роботі використовуються наступні функції: close (закрити файл), lseek (перепозиціювання вказівника файлу в задану позицію), open (відкрити файл), read (читати дані з файлу), write (записати дані у файл). Оголошення для цих функцій розташовані в заголовному файлі io.h.
Перед виконанням операцій з файлом він повинен бути відкритий. Файл може бути відкритий для читання та/або запису в текстовому або двійковому вигляді.
Для відкриття файлу використовуємо функцію open. Ця функція повертає хендл файлу, який використовується при подальших операціях з файлом. При виклику функції open слід присвоїти значення, що повертається, цілочисельній змінній і використовувати цю змінну для звернення до відкритого файлу.
Прапори, що використовуються у функціях введення виведення низького рівня, містяться в заголовному файлі fcntl.h. В деяких випадках файли types.h і stat.h також використовуються для роботи з файлами.
Функція open має наступний формат
int open (char *pathname, int oflag[, int pmode]),
де pathname - ім'я файлу, що відкривається, оflag - режим відкриття. Аргумент oflag є цілим виразом, сформованим комбінацією однієї або більше наступних заголовних констант, визначених в fcntl.h (коли задається більш однієї заголовної константи, вони розділяються операціями АБО (|)):
O_APPEND - перерозташувати вказівник файлу на кінець файлу перед кожною операцією запису;
O_CREAT - створити і відкрити новий файл для запису, не дає результату, якщо файл вже існує;
O_EXCL - функція повертає помилковий код -1, якщо визначений в pathname файл вже існує; Застосовується тільки разом з O_CREAT;
O_RDONLY - відкрити файл тільки для читання; якщо цей прапор був заданий, ні O_RDWR, ні O_WRONLY не можуть бути задані;
O_RDWR - відкрити файл для читання і запису; якщо цей прапор був заданий, ні O_RDONLY, ні O_WRONLY не можуть бути задані;
O_TRUNС - відкрити і звузити існуючий файл до нульової довжини; файл повинен мати доступ для запису. Вміст файлу втрачається;
O_WRONLY - відкрити файл тільки для запису; якщо цей прапор був заданий, ні O_RDONLY, ні O_RDWR не можуть бути задані;
O_TEXT - відкрити файл в текстовому режимі (Комбінація символів повернення-каретки/переведення-рядка (CR/LF) перетворюється у переведення рядка (LF) при введенні; символ LF переводиться в комбінацію CR/LF при виведенні. Символ Ctrl-Z є ознакою кінця файлу.);
O_BINARY - відкрити в двійковому режимі. (Вказані вище переведення забороняються. Символ Ctrl-Z не є ознакою кінця файлу.).
Аргумент pmode потрібен тільки тоді, коли визначений режим відкриття O_CREAT. Якщо файл існує, pmode ігнорується. У іншому випадку pmode визначає спосіб доступу до файлу, що встановлюється після його першого закриття. Pmode є цілий вираз, що містить одну або обидві константи S_IWRITE і S_IREAD, визначених у файлі stat.h. Коли обидві константи задаються, вони розділяються операцією АБО(|). Рmode приймає наступні значення:
S-IWRITE - доступ для запису;
S-IREAD - доступ для читання;
S-IREAD | S-IWRITE - доступ для читання і запису.
Якщо доступ для запису не був заданий, файл відкривається тільки для читання
Функція повертає хендл відкритого файлу і -1 при помилці. При невдалому відкритті системна змінна errno встановлюється в одне з наступних значень:
EACCES - задане ім'я шляху є каталогом, або спроба відкрити для запису файл, який призначений тільки для читанн;
EEXIST - були визначені O_CREAT і O_EXCL прапори, але файл вже існує;
EMFILE - немає більше доступних файлів handle (дуже багато відкритих файлів);
ENOENT -файл або ім'я шляху не знайдено.
Приклад.
#include <fcntl.h>
#include <types.h>
#include <stat.h>
#include <io.h>
#include <stdlib.h>
main()
{ int fn1, fn2;
fn1 = open("data1", O_RDONLY);
if (fn1 == -1) реrror("спроба відкрити ввідний файл невдала");
fn2 = open("data2”, O_WRONLY|O_TRUNC|O_CREAT, S_IREAD|S_IWRITE);
if (fn2 == -1) реrror("спроба відкрити вивідний файл невдала");
}
Для виведення повідомлень про помилку використовується функція реrror, яка разом з вказаним в ній текстовим рядком виводить в стандартний потік помилок stderr системне помилкове повідомлення, пов'язане із змінною errno.
Відкриті файли автоматично закриваються, при нормальному завершенні. Для примусового закриття файлів використовується функція int close(int handle), де handle - хендл файлу, що закривається.
Функція повертає 0, якщо файл успішно був закритий, і -1, якщо хендл handle є недійсним аргументом. При невдалому закритті системна змінна errno встановлюється в EBADF - недійсне значення хендла або була спроба записати у файл або пристрій, відкриті тільки для читання.
Приклад.
#include <io.h>
#include <fcntl.h>
main()
{ int fh;
fh = open("data",O_RDONLY);
close(fh);}
Функція lseek переміщає вказівник запису/читання файлу в нове положення, з якого почнеться наступна операція. Формат функції
long lseek(int handle, long offset, int origin)
де handle - хендл файлу, а параметр origin визначає як використовується зсув offset для визначення нового положення вказівника:
SEEK_SET - від початку файлу;
SEEK_CUR - від поточної позиції вказівника файлу;
SEEK_END від кінця файлу.
Вказівник може бути переміщений за кінець файлу, проте файл змінить свої розміри тільки після операції запису даних в нову позицію.
При вдалому завершенні функція повертає зсув в байтах нової позиції покажчика від початку файлу. При помилці повертається -1L, при цьому системна змінна errno встановлюється в одне з наступних значень:
EBADF- (див. вище)
EINVAL - недійсне значення для origin, або позиція, щовизначається зсувом offset, вказує на дані, розташовані до початку файлу.
Приклад.
#include <io.h>
#include <fcntl.h>
#include <stdlib.h>
main()
{ int fh; long роsition;
fh = open("data", O_RDONLY);
роsition = lseek (fh, 0L, SEEK_SET);
if (роsition == -1L) реrror("переміщення на початок невдале");
/* знайти поточну позицію */
роsition = lseek (fh, 0L, SEEK_CUR);
if (роsition == -1L) реrror ("переміщення на поточну позицію невдале");
роsition = lseek(fh, 0L,SEEK_END);
if (роsition == -1L) реrror("переміщення на кінець невдале");}
Для читання і запису даних застосовуються функції read і write. Ці операції починають свої дії з поточної позиції покажчика у файлі, яка змінюється при кожній операції читання або запису. Для запису інформації використовується функція write, яка має наступний формат:
int write(int handle, char *buffer, unsigned count),
де handle - хендл файлу, куди буде записано count байтів інформації з буфера buffer.
Після операції запису вказівник збільщується на число записаних байт. Якщо файл був відкритий для додавання (APPEND), операція починається з кінця файлу.
Функція повертає число дійсно записаних байт. Значення, що повертається, може бути додатним, але менше count. Повернення числа -1 свідчить про помилку, при цьому змінна error встановлюється в одне з наступних значень:
EACCES - файл захищений від запису;
EBADF - недійсний хендл;
ENOSPC - недостатньо дискової пам'яті.
Приклад.
#include <io.h>
#include <stdio.h>
#include <fcntl.h>
char buffer[30000];
main()
{ int fh; unsigned nbytes = 30000;
int byteswritten;
if ((fh = open("с:/data/cont.dat",O_WRONLY)) == -1) {
реrror("невдала спроба відкрити вивідний файл");
exit(1); }
if ((byteswritten = write(fh, buffer, nbytes)) == -1){
реrror("Помилка запису");
else printf("Записано %d байтов\n", byteswritten);
}
Функція read застосовується для читання інформації з файлу і має формат:
int read (int handle, char * buffer, unsigned count);
де handle - хендл файлу, з якого ця функція намагається прочитати count байтів в буфер buffer. Операція читання починається з поточної позиції вказівника. Після читання вказівник файлу вказує на наступний непрочитаний символ.
Функція повертає число дійсно прочитаних символів, яке може бути менше ніж count, якщо у файлі залишалось недостатнє число байт. Якщо файл був відкритий в текстовому вигляді, значення, що повертається, може не відповідати числу дійсно прочитаних байтів. Це пояснюється тим, що кожна комбінація поверення-каретки/новий_рядок (LF) замінюється символом нового рядка (LF), і лише символ нового рядка зараховується в значення, що повертається.
При спробі прочитати за кінцем файлу повертається 0. При помилці повертається число -1 і системна змінна errno приймає значення: EBADF (Див. вище)
Приклад
#include <io.h>
#include <stdio.h>
#include <fcntl.h>
char buffer [60000];
main ()
{int fh;
unsigned int nbytes = 60000, bytesread;
if ((fh = open ("conf.dat", O_RDONLY)) == -1) {
реrror ("спроба відкрити ввідний файл невдала");
exit (1); }
if ((bytesread = read (fh, buffer, nbytes)) == -1) реrror (" ");
else printf ("прочитано %u байтів з файла\n", bytesread);
}
При написанні системи управління прямим доступом до файлу нам знадобиться функція
int chsize(int handle, long size),
яка розширює або звужує файл, зв'язаний з хендлом handle до довжини, визначеної в size. Файл повинен бути відкритий з доступом для запису. Якщо файл розширяється, він заповнюється нульовими символами.
При успішній зміні довжини функція повертає 0, при помилці -1 і змінна errno встановлюється в одне з наступних значень:
EACCES - вказаний файл тільки для читання.;
EBADF - (див. вище).
ENOSPC - недостатньо місця на диску.
Приклад.
#include <io.h>
#include <fcntl.h>
#include <types.h>
#include <stat.h>
#define SIZE 32768L
main()
{int fn, result;
fn = open("data", O_RDWR|O_CREAT, S_IREAD|S_IWRITE);
result = chsize (fn, SIZE); }
Швидкість роботи дискового накопичувача значно нижча швидкості роботи центрального процесора. Для збільшення еффективностиі введення-виведення широко використовується буферизація. Суть її полягає у відкладанні фізичної роботи з диском на більш пізній термін. Програма користувача веде обмін даних з буфером і лише у тому випадку, коли необхідні логічні записи, що не розташовані в буфері, відбувається фізичний обмін з диском.
Для буферизації рекомендується використовувати буфер з довжиною, що кратна розміру фізичного сектора диска, рівному 512 байт. Обмін даними з диском ведеться блоками об’ємом в один сектор. Це підвищить швидкість обміну Вашої програми з диском.
Для визначеності припустимо, що файл містить інформацію про членів деякого колективу і кожний логічний запис має два поля: Прізвище - 14 символів і рік народження - цілий тип int -2 байта. Сумарна довжина запису rcrdsz =16 байт.
Зблокуємо записи в блоки по 512 байт. В 0-й блок входять 0-а, 1-а... 31-а записи. В 1-й блок входять 32-а, 33-а... 63-а записи тощо. Обмін інформацією з диском проводитимемо блоками, тобто розмір буфера рівний розміру блоку і рівний 512 байт.
Нехай Ваша програма працює з i- м записом. Він знаходиться в блоці bl=i*rcrdsz/512 (цілочисельне ділення) і починається в цьому блоці з байта n=i*rcrdsz%512. Якщо була задана адреса buf початку буфера обміну, в якому розташований bl -й блок, то k=buf+n указує на початок i-го запису файлу в буфері buf. Тут k і buf мають тип char*.
Логічний запис доцільно розглядати як структуру. В нашому випадку вона має вигляд:
struct _rec {char name[14]; /* Прізвище */
int gr;}; /* Рік народження*/
Структура _rec визначає вміст логічного запису з точки зору програміста. На диску вона зберігається у вигляді послідовності 16-ти, що не відрізняються між собою, байт, тобто логічний запис може бути розглянутий з цих двох точок зору. Відповідною структурою даних, що відображає цю неоднозначність, є об’єднання union. В нашому випадку можна рекомендувати наступну конструкцію:
union _bufrec {char bufrec[16];
struct _rec rec;} rbuf;
Тоді rbuf,bufres - це послідовність з 16-ти байт, яка є логічним записом rbuf.rec, що складається з двох полів rbuf.rec.name (прізвище) і rbuf.rec.gr (рік народження). Або в іншому трактуванні: вміст полів rbuf.rec.name і rbuf.rec.gr логічного запису rbuf.rec можуть бути розглянуті як послідовність з 16-ти байт rbuf.bufrec.
Всі дані, що використовуються при прямому доступі до файлу, доцільно зберігати як єдине ціле. Для цього визначимо тип даних AFILE.
typedef struct afile {
char *buf; /* Буфер обміну*/
int bz; /*Номер блоку, завантаженого в буфер обміну, спочатку -1*/
int w; /*Якщо в buf був виконаний запис, то w=1 інакше w=0*/
int rcrdsz; /* Довжина логічного запису*/
int numrec; /* Кількість логічних записів у файле*/
int handler; /* Хендл файлу*/}
AFILE;
На початку роботи з файлом прямого доступу слід його відкрити, заповнивши відповідним чином структуру, на яку вказує AFILE* ар.
При роботі з i-им логічним записом необхідно обчислити номер відповідного блоку bl=i*rcrdsz/512 (цілочисельне ділення) і визначити початок запису в цьому блоці n=i*rcrdsz%512. Потім слід перевірити чи не знаходиться логічний запис в буфері (bl==ap->bz). Якщо ні, то дивимося чи змінювався вміст буфера (ap->w==1). Якщо змінювався, тоді слід скинути буфер на диск в ap->bz -й блок, тобто записати вміст буфера ap->buf у файл починаючи з ap->bz*512 -го байта. Далі (при bl!=ap->bz) слід записати в буфер ap->buf bl -й блок файлу, тобто ввести в буфер з файлу 512 байт, починаючи з 512* bl -й позиції, встановити новий номер завантаженого в буфер блоку ap->bz=bl і скинути прапорець зміни буфера ap->w=0. Після цього необхідний логічний запис буде знаходитися в буфері, починаючи з n -го байту.
Для цілісності інформаційної структури файлу прямого доступу рекомендується в початок файлу помістити два цілих двобайтових числа: довжину логічного запису в байтах і число логічних записів.
Практична частина.
1. Вивчити теоретичну частину. Вміти відповідати на контрольні питання.
2. Для організації системи прямого доступу до файлу слід pозpобити наступні функції:
2.1. Функція створення файлу прямого доступу
int асreate (char* name, int rcrdsz, int numrec),
де name - ім'я створюваного файлу, rcrdsz - розмір логічного запису в байтах, numrec - кількість логічних записів у файлі.
Функцію слід організувати таким чином.
За допомогою функції open перевіряється існування файлу з ім'ям name. Якщо файл є на диску, функція асreate повертає -1.
Використовуючи функцію open, створюємо бінарний файл name з доступом для запису і читання.
Застосовуючи 2 рази функцію write, записуємо в перші 4 байта файлу розмір логічного запису в байтах і кількість логічних записів.
Змінимо розмір створеного файлу до величини 4+rcrdsz*numrec (функція chsize).
Закриємо файл (функція close).
2.2. Функція для відкриття створеного файлу прямого доступу
AFILE *aopen(char *name),
де name - ім'я файлу.
Алгоритм роботи, що рекомендується.
Зарезервувати пам'ять для структури AFILE
AFILE *ap=(AFILE*)malloc(sizeof(AFILE)).
Заповнити поля структури, для чого:
- виділити 512 байт для буфера обміну ap->buf=(char*)malloc(512);
- відкрити за допомогою функції open двійковий файл name з доступом для запису і читання і присвоїти отриманий хендл полю структури ap->handler;
- використовуючи двічі функцію read прочитати з файлу розмір логічного запису і кількість логічних записів у файлі, заповнивши поля ap->rcrdsz і ap->numrec;
- встановити ознаку зміни буфера обміну ap->w в 0;
- присвоїти полю ap->bz -1.
Повернути в програму вказівник ар на структуру AFILE.
2.3. Функція для обміну інформацією між програмою користувача і файлом прямого доступу
int areadwrite(AFILE *ap,int nr, char* rec, int mode),
де ар - вказівник на структуру, що описує файл прямого доступу, з яким ведеться робота, nr - номер логічного запису у файлі, з яким проводиться обмін інформацією, rec – буфер користувача, рівний за розміром довжині логічного запису і що використовується для введення-виведення записів, mode - режим обміну (0 - читання, 1 - запис).
Функція повинна виконувати наступні дії.
Обчислити номер блоку bl=nr*rcrdsz/512, в якому розташований логічний запис з номером nr і початок запису в цьому блоці n= nr *rcrdsz%512.
Перевірити чи не знаходиться логічний запис nr в буфері (bl==ap->bz). Якщо ні, то дивимося чи змінювався вміст буфера (ap->w==1). Якщо змінювалося, то слід скинути буфер на диск в ap->bz -й блок, тобто, використовуючи функції lseek і write, записати вміст буфера ap->buf у файл починаючи з 4+ap->bz* 512-го байта. Далі (при bl!=ap->bz) слід:
- записати в буфер ар ->buf bl- й блок файлу, тобто застосовуючи функції lseek і read, ввести в буфер з файлу 512 байт, починаючи з 4+512*bl -ї позиції;
- встановити новий номер ap->bz=bl завантаженого в буфер блоку;
- скинути прапорець зміни буфера ap->w =0. Логічний запис nr знаходиться в буфері ap->buf, починаючи з n -го байта і з ним можна вести обмін інформацією залежно від значення змінної mode;
- при читанні (mode=0), дані переписуються з буфера обміну в призначений для користувача буфер:
for(i=0;i<rcrdsz;i++)rec[i]=(ap->buf+n)[i].
- при запису (mode=1) проводиться обмін інформацією в зворотньому напрямі:
for(i=0;i<rcrdsz;i++)(ap->buf+n)[i]=rec[i]
і встановлюється ознака зміни вмісту буфера обміну ap->w=1.
2.4. Функція закриття файлу прямого доступу
int асlose(AFILE *ap),
де ар - вказівник на структуру AFILE, яка описує файл прямого доступу, що закривається.
Функція працює таким чином.
Якщо вміст буфера ap->buf змінювався (ap->w==1), то слід встановити вказівник запису-читання на початок завантаженого блоку (4+ap->bz*512) і записати буфер на диск. Хендл файлу знаходиться в ap->handler.
За допомогою функції free слід послідовно звільнити пам'ять, що зайнята буфером ap->buf, закрити файл з хендлом ap->handler і звільнити пам'ять від структури AFILE, на яку вказує змінна ар.
3. Для перевірки правильності роботи системи прямого доступу до файлу слід використовувати наступну функцію main
typedef struct afile {
char *buf;
int bz;
int w;
int rcrdsz;
int numrec;
int handler;} AFILE;
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <stat.h>
#define R 0
#define W 1
struct _rec {char name[14]; int gr;};
int асreate (char*, int, int); /*Прототипи */
AFILE *aopen(char *) *ap;
int areadwrite(AFILE*, int, char*, int);
int асlose(AFILE *ap); /* функцій */
main()
{ int i, nr;
char s[13],c,c1;
union _bufrec {char bufrec[16]; /*Буфер*/
struct _rec rec;} rbuf; /* rористувача */
printf("\nВведіть ім'я нового файлу прямого доступа\
(100 записів по 16 байт): ");
gets(s);
if(-1==acreate(s,16,100))
printf("\nЧи будете працювати з існуючим файлом %s!",s);
ap=aopen(s); /* Відкриття файлу прямого доступа*/
do { /* Основний цикл*/
for(i=0;i<16;i++)rbuf.bufrec[i]='\0'; /* Обнулення логічного запису*/
puts("\nHомеp запису?");
scanf("%d",&nr);
areadwrite(ар, nr, rbuf.bufrec, R); /* Читання логічного запису */
/* Виведення запису на экран*/
printf("\nЗапис #%d. Вміст полів:\n Ім’я=\" %s\". \
Рік народження = %d",nr,rbuf.rec.name,rbuf.rec.gr);
puts(" \nЧи будете змінювати/формувати запис (у/n)?");
c=getche();
if(c=='y')
{puts("\nПрізвище?"); /*Введення полів логічного запису з клавіатури*/
scanf("%s",rbuf.rec.name);
puts("\nРік народження?");
scanf("%d",&rbuf.rec.gr);
areadwrite(ар, nr, rbuf.bufrec, W); /* Запис логичного запису на диск */
}
puts("\nЧи будете працювати з файлом ще (у/n)?");
c1=getche();
}
while(c1=='y');
асlose(ар); /* Закриття файла*/
}
Зверніть увагу на використовування змінної типу об’єднання rbuf.
Контрольні питання.
1. Що таке дескриптор файлу і його хендл?
2. В чому полягає процес відкриття файлу?
3. Що таке логічний запис?
4. Охарактеризуйте послідовний доступ до файлу.
5. В чому суть довільного доступу до файлу?
6. Який режим доступу до файлів забезпечують системи UNIX і MS DOS?
7. Яку роль в організації файлових систем відіграє вказівник запису/читання?
8. Які функції дозволяють відкривати і закривати файли?
9. Яка функція і як забезпечує установку позиції запису/читання у файлі?
10. Як прочитати (записати) інформацію в (з) файл(а)?
11. Чи можна змінювати розмір існуючого файлу?
12. Навіщо застосовують буферизацію при роботі з файлами?
13. Висловити алгоритм буферизації.
14. Привести алгоритм організації прямого доступу до файлу.
15. Навести приклади форматів логічних записів.
16. Які типи даних рекомендується застосовувати при роботі з логічними записами?
17. Який виграш дає робота вживання структури AFILE з файлами прямого доступу?
18. Яку інформацію і навіщо рекомендується додавати в початок файлу прямого доступу?
Лабораторна робота №6.