Реферат: Фізичні файли та файлові змінні

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

Вираз (<11, 12>, 2, W)позначає файл із двох елементів:

F

11

12

­

Стан

W

Обидва вони недоступні, файл перебуває в стані запису, до нього можна додати новий елемент (із номером 2) і присвоїти йому якесь значення.

Вираз (<>, 0, R) позначає порожній файл, у якому немає елементів.ç

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

І останнє зауваження. Елементи типізованих файлів можуть мати будь-який скалярний чи структурний тип, окрім файлового чи структурного з елементами-файлами. Файли також не можуть бути елементами інших структур. Наприклад, недопустимі означення типів

type FF = file of file of якийсь тип;{???}

FA = array [ 1..10 ] of file of якийсь тип; {???}

FAF = file of FA {???}.

2. Послідовний запис у типізовані файли

Перш, ніж записувати в файл, слід відкрити його для запису. Це задається процедурою REWRITE. Після виклику ReWrite(f) значення f подається як (<>, 0, W), тобто незалежно від попереднього значення f послідовність у файловій змінній стає порожньою:

F

­

стан

W

Значення 0 вказівника доступного елемента свідчить про те, що можна записати нове значення в перший, тобто з номером 0, елемент файла. Ця процедура викликається для створення нового файла або поновлення старого зі знищенням даних, що були в ньому. Після її виконання файл називається встановленим у початковий стан для запису.

Запис у файл задається процедурою WRITE. При виконанні її виклику

write ( f, вираз-типу-компонентів-файла)

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

program ...

var f : file of integer; x : integer

begin ...

rewrite(f); x:=2;

write(f, 1); write(f, x); write(f, x*x);

...

end.

файлова змінна f має значення, що подається як (<1, 2, 4>, 3, W).

Узагалі, значення (<f0 , … , fn-1>, n, W) файлової змінної f при виконанні write(f, вираз) міняється на (<f0, … , fn-1, V>, n+1, W), де V позначає значення виразу.

У виклику write можна вказувати довільне число аргументів-виразів того самого типу: write ( f, вираз1, ... , виразN ). Такий виклик виконується насправді як послідовність

write(f,вираз1); … ; write(f,виразN).

Наприклад, замість write(f, 1); write(f, x); write(f, x*x) можна написати write(f, 1, x, x*x).

Підкреслимо, що процедуру writeln не можна застосовувати до типізованих файлів. Вона призначена лише для роботи з текстами.

Приклад 13.1. Треба створити файл із такими даними про студентів групи: прізвище та ім’ я студента, а також середній бал його успішності.

Дані про студента можна подати записом типу

Student = record

SName, Name : string[20];

Ball : real

end.

Зв’ язування та встановлення файла в початковий стан для запису оформимо процедурою OpenFile, а створення – процедурою CreatFile у такій програмі:

program InPutGroup;

type

Student = record

Sname, Name : string[20];

Ball : real;

end;

var

Fi : file of Student; { Файлова змінна Fi – інформаційний файл }

FileName: string; { Змінна для введення імені файла }

procedure OpenFile;

begin

writeln('Задайте ім''я файла, що буде створюватися: ');

readln(FileName);

assign(Fi, FileName);

rewrite(Fi);

end;

procedure InPutFile;

var St : Student;

Ch : char;

begin

repeat

writeln('Задайте дані про студента:');

write('Прізвище>'); readln(St.SName);

write('Ім''я>'); readln(St.Name);

write('Середній бал успішності>'); readln(St.Ball);

write(Fi, St); {***}

write('Чи треба вводити дані про нового студента? "Y"/"N"> ');

readln(Ch);

until (Ch = 'n') or (Ch = 'N');

close(Fi);

end;

begin

writeln('Програма створення файла даних про успішність');

openfile; { Виклик процедури відкривання файла }

creatfile; { Виклик процедури створення файла }

end.

3. Послідовне читання типізованих файлів

Для того, щоб читати вже створений типізований файл, треба відкрити його для читання викликом процедури RESET(f). Після її виклику файлова змінна установлюється в початковий стан для читання, а номером доступного елемента стає 0 незалежно від того, чи є взагалі елементи в файлі. Значення f можна подати як (F, 0, R), тобто

F

f0

f1

...

­

Стан

R

Якщо F є порожньою послідовністю, F=<>, то спроба читання з файла завершується аварійно, оскільки доступного елемента просто немає!

Файл із диску можна читати тільки після установлення файлової змінної в початковий стан для читання, тобто установлення обов’ язкове. Можливість чи заборона установлення файлової змінної, зв’ язаної з клавіатурою, залежить від системи програмування. У системі Турбо Паскаль таке установлення можливе, хоча й не обов’ язкове.

Зазначимо, що в програмі може бути довільна кількість викликів процедури reset, і що система Турбо Паскаль дозволяє після виконання її викликів не тільки читати з файла, а й записувати в нього, тобто змінювати його перший елемент. І взагалі, система дозволяє змінювати за допомогою write доступний елемент файла, яким би не було його місце в послідовності і за будь-якого стану файла.

Читання доступного елемента файла задається процедурою READ. Її виклик має вигляд

read(f, v),

де v – ім’ я змінної того ж типу, що і в елементів файла. В результаті значення доступного елемента присвоюється цій змінній, а вказівник доступного елемента переміщується на наступний елемент.

Наприклад, при читанні read(f, x) файлової змінної f із значенням

(<11, 12, 13>, 0, R)

змінна x набуває значення 11, а значення f подається як

(<11, 12, 13>, 1, R),

тобто доступним стає елемент 12.

Узагалі, якщо файл містить n елементів, пронумерованих від 0 до n-1, і номер доступного компонента i менше n, то виклик read(f, x) задає присвоювання змінній x значення i-го елемента та перехід від значення файлової змінної (F, i, R) до (F, i+1, R). Якщо ж i=n, то кажуть, що файл f прочитано, або вичерпано (зокрема, коли він порожній, тобто F = <>). За такого значення i виклик read призводить до аварійного завершення програми.

У виклику процедури read можна вказувати довільну кількість аргументів, що є іменами однотипних змінних:

read ( f, v1, v2, … , vN ).

Такий виклик виконується насправді як послідовність викликів

read(f, v1 ); read(f, v2 ); ... read(f, vN ).

Зрозуміло, треба гарантувати при цьому, що в файлі залишилося достатньо непрочитаних елементів.

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

Визначення того, чи прочитано вже файл, задається функцією EOF. За виклику eof(f) повертається бульове значення false, якщо доступний який-небудь елемент файла, тобто значення виразу i<n у значенні файлової змінної (<f0, … , fn-1>, i, R). Значення true повертається за i=n, що можливо після читання всіх елементів файла без установлення його в початковий стан.

Виклик функції eof дозволяє визначити, чи є ще у файлі непрочитані елементи, та запобігти читання з вичерпаного файла.

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

Приклад 2. Напишемо програму обчислення середнього арифметичного A цілих чисел непорожнього файла nums.dat та запису в інший файл всіх його чисел, менших A.

Розв'яжемо задачу в такий спосіб:

1) прочитати всі числа з файла, обчислити їх суму й кількість і визначити A;

повторно прочитати всі числа, копіюючи з них лише менші від A.

Нехай числа записано в файлі цілих з ім'ям nums.dat, а числа, менші за середнє, переписуються в файл littls.dat. Наведені дії задаються програмою

program numbers;

var f , g : file of integer;

v : integer; a : real;

n : integer;

begin

assign ( f, 'nums.dat' );

{1}reset ( f );

read ( f, v ); {читання першого елемента без перевірки !}

a:=v; n := 1;

while not eof ( f ) do

begin {з виклику eof(f) повернулося false,}

{тому можна читати доступний елемент}

read ( f, v );

a := a + v; n := n + 1

end;

{з виклику eof(f) повернулося true}

a := a/n;

{2}reset ( f );

assign(g, 'littls.dat'); rewrite(g);

while not eof ( f ) do

begin

read ( f, v ); if v < a then write(g, v )

end;

close ( f ); close(g);

end.

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

Приклад 3. Вивести на екран комп’ ютера дані про студентів з файла, створеного за програмою з прикладу 13.1.

Природньо розглядати файл як послідовність записів типу Student. Його елементи по одному читаються в допоміжну змінну St та значення її полів (прізвище, ім’ я й середній бал), що мають базовий тип або є рядками, виводяться на екран із його попереднім очищенням. Очищення екрану задається викликом процедури CLRSCR, що входить до складу модуля Crt. Після кожного виведення для одержання нових даних слід натиснути на клавішу Enter.

У наступній програмі використовується змінна IOResult, означена в модулі Dos. Вона набуває ненульового значення, якщо при виконанні процедури Reset виникла якась помилка, наприклад, зв’ язана з тим, що користувач задав ім’ я неіснуючого файла. Перед її викликом вимикається режим перевірки правильності введення-виведення, оскільки в цьому режимі за помилкового виконання Reset програма аварійно завершується. Після виклику Reset режим перевірки вмикається знов.

program OutPutGroup;

uses Crt, Dos; { Підключення модулів Crt та Dos }

type Student = record

Sname, Name : string[20]; Ball : real;

end;

var Fi : file of Student;

FileName: string; { Змінна для введення імені файла }

procedure OpenFile;

var Rez : Integer; Ch : char;

begin

Rez:=1;

while Rez <> 0 do { Rez=0 – ознака того, що введено} {правильне зовнішнє ім’я файла}

begin

writeln('Задайте ім''я файла'); readln(FileName);

assign(Fi, FileName);

{$I-} {Вимкнення контролю правильності читання/запису}

reset(Fi);

{$I+} { Увімкнення контролю }

Rez:=IOResult;

if Rez <> 0 then

begin

writeln('Перевірте правільность імені файла !');

writeln('Чи буде повторне задання імені? "Y"/"N":');

readln(Ch);

if (Ch = 'n') or (Ch = 'N') then halt(0);{Вихід із програми}

end;

end;

end;

procedure OutPutFile;

var St : Student; Ch : char;

begin

writeLn('Чи бажаєте дивитися дані про студентів ? "Y"/"N" ');

readln(Ch);

if (Ch = 'Y') or (Ch = 'y') then

begin

while not eof(Fi) do

begin

read(Fi, St); clrscr;

writeln('Прізвище : ', St.SName);

writeln('Ім''я: ', St.Name);

writeln('Середній бал: ', St.Ball);

readln;

end;

end;

close(Fi);

end;

begin

clrscr; writeln('Програма друкування даних про студентів');

openfile; outPutfile;

end.

Задачі

1.* Пояснити, що задає та як використовується пpогpама

program filcrout;

type Tel = record nam : string; num : integer end;

var f : file of Tel; x : Tel; s : string; eel : boolean;

procedure readel ( var x : Tel );

begin

x.num:=0; readln ( x.nam);

if x.nam <> '' then readln ( x.num )

end;

begin

writeln ( 'Введіть ім''я файла:' ); readln ( s );

assign ( f, s ); rewrite ( f );

repeat

readel ( x ); eel := (x.nam = '');

if not eel then write ( f, x );

until eel;

reset(f);

while not eof ( f ) do

begin

read ( f, x ); writeln ( x.num, ': ', x.nam )

end

end.

2.* Переписати програму з прикладу 13.2, щоб у разі порожнього файла її виконання не завершувалося аварійно.

3. Переписати програму з прикладу 13.2, щоб числа не копіювалися в інший файл, а друкувалися на екрані.

4.* Написати пpоцедуpу пpисвоювання файлів шляхом копіювання.

5.* Написати функцію пеpевіpки побайтової pівності двох файлів.

6.* Написати пpоцедуpу дописування до елементів пеpшого файла елементів другого, із зберіганням pезультату

а) в новому файлі; б) в першому файлі.

7.* Написати пpоцедуpу виведення змісту файла з даними про студентів на екpан "стоpінками": після друкування на екрані даних про чергових 5 студентів виводиться запит щодо продовження, і виконання програми призупиняється до того, як користувач підтвеpдить або не підтвердить пpодовження.

4. Прямий доступ у системі Турбо Паскаль

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

Але послідовний доступ елементів не завжди зручний. Чи не замислювався читач над тим, як запрограмувати читання з типізованого файла елемента за його номером або його заміну, додавання чи вилучення ?

Зрозуміло, що задати читання елемента за номером k можна так:

reset(f);

for i:=1 to k-1 do read(f, x); {пропущено k-1 елемент – доступний k-й}

read(f, x).

Для заміни елемента файла за його номером k можна "вийти на нього" шляхом читання попередніх. Далі можна скористатися одним недоліком системи Турбо Паскаль. Справа в тім, що система дозволяє в стані читання записувати в файл значення змінних (і лише змінних!). Отже, заміну елемента можна описати так:

reset(f);

for i:=1 to k-1 do read(f, x);

{пропущено k-1 елемент - доступний якраз k-й}

x:=...; write(f, x).

Описати в такому ж дусі вилучення й додавання елемента до файла ми залишаємо вправою для наддопитливих читачів. Але все це "штучки", якими користуватися не варто.

Натомість розглянемо прямий доступ до елементів файла. Його суть у тім, що елементи задаються номерами в послідовності, яка утворює файл. Такий доступ здійснюється за допомогою спеціальних підпрограм.

Основною є процедура SEEK. У її виклику задається ім’ я файлової змінної та номер того елемента файла, який стає доступним після виконання виклику. Номер задається виразом типу LongInt. Наприклад, після виклику

Seek ( f, 2)

доступним стає третій елемент, оскільки нумерація починається з 0:

f0

f1

f2

f3

...

fN



  • Сторінка:
  • 1
  • 2
  • 3
  • 4