.
.
.
.
.
.
Write(ім’я, параметри);
Close(ім’я);
Оператор виведення для запису даних у файл володіє усіма властивостями звичайного оператору Write. Якщо записано Write(napaм);, то дані виводяться на екран дисплею. А якщо записано Write (ім'я, парам);, то дані записуються у файл, який зберігається на диску. Rewrite в деяких версіях має ті ж параметри, що й Reset.
Приклад: дано type рядок = array [1..100] of char;
Текст=file of char;
Описати процедуру цифри (s,t), яка записує у текст t всі цифри з рядку s.
Procedure цифри (var t: text; s:рядок);
Var і: integer;
Begin
Rewrite (t);
For i:=1 to 100 do
If s[i] in [‘0’..’9’] then
Write(t,s[i]) ;
Close(t);
End;
Приклад: a=150; b=12.6. Записати у файл dl.dat рядок у вигляді:
а=150_ _ _ _ _b=12.6
program рr;
type k:file of real;
var s:k;
a, b: real;
12: integer;
chislo:real;
begin
12: =1;
Write(‘Введіть a і b’);
readln(a ,b) ;
rewrite(s, ‘dl’, ‘dat’, 12);
write(s, ‘a=’',а:5, ‘_’:5, ‘b= ‘, b:4:1);
close (s);
end.
Оператор Rewrite відкриває файл для запису в нього даних, так як для запису одного рядку цілком досить одного блоку, то змінній 12 присвоюється значення рівне 1 (1блок=256 байтів).
Над файлами можна виконувати різні дії. Іноді необхідно читати з одного
файлу, а записувати в другий.
Наприклад:
Дані вводяться із файла (f1) та виводяться в файл (f2). Змінна х приймає значення одного символу із файла. Значення деякої змінної y записується в файл (f2).
Program k1;
Type f=Text;
Var f1, f2:f;;
x,y:char;
begin
reset (f1);
rewrite(f2);
read(f1,x);
.
. {дії над змінними х та у}
.
write(f2,y);
close (f2);
close(f1);
end.
При використанні послідовних файлів не можна одночасно відкривати один і той самий для читання і запису. Якщо є така необхідність, то спочатку відкривається файл, обробляються його дані і закривається. Потім відкривають цей же файл заново, обробляють його та закривають.
Задача: Є відомість результатів екзаменів у групі. Будемо вважати її вхідним файлом з ім'ям kol. Скласти програму створення вихідного файлу з ім'ям rez, в який потрібно записати вихідну відомість і обчислити середній бал.
Прізвище
| Оцінка
|
Іванов
Пєтров Сідоров
| :5
:4
:3
|
Середній бал
| :4
|
Кіл. студентів
| :3
|
Program ABC;
Var f1,f2: text; {файлові змінні}
l1,l2:integer; {кількість блоків}
n: integer; {лічильник кіль кості студентів}
sum:real;
sim: char; {симв. змінна}
с: integer; {оцінка}
sr:real; {середній бал}
Begin
l2: =1; {один блок для f1}
l1:=1;
reset(f1, ‘kol’, ‘pas’, l1);
rewrite (f2,’rez’, ‘pa`s’, l2);
n:=0; sum:=0;
while not eof(fl) do
begin
while not eoln(fl) do
begin
read(fl,sim); {чит. симв. із f1}
write(f2, sim); {запис симв. в f2}
if sim= ‘:’ then
begin
read(fl,c); {читаєм оцінку iз f1}
write(f2,c:3); {запис оцінки в f2}
sum: =sum+c;
n=n+1;
end;
end;
readln(f1);
writeln(f2);
end;
sr:=sum/n;
writeln(f2, 'cep.6= ', sr:5:2);
witeln(f2, 'кіл-ть cm. = ', n:2);
writeln(f2, 'результат в файлі kol.pas');
close (f2);
close (f1);
end.
В розділі операторів спочатку задається число блоків l2 для вихідного файлу. Далі визивається стандартна процедура Reset з параметрами
f1 - файлова змінна;
‘kol’ - ім'я фізичного вхідного файла;
'pas' — розширення імені kol;
l1 - змінна, що отримує значення в результаті виконання процедури Reset. Це значення = числу блоків які займає вхідний файл kol на диску. Потім визивається процедура Rewrite з параметрами:
f2 - вихідний файл;
'rez' - ім'я фізичного вихідного файлу;
'pas' - розширення;
l2 - змінна, що резервує кількість блоків на диску для вихідного файлу.
Вхідний файл являє собою послідовність рядків. Читання, обробка та запис відомості виконується за допомогою складного циклу: зовнішнього, в якому виконується перевірка на кінець файлу даних та внутрішнього, в якому виконується перевірка на кінець поточного рядка файла. Зовнішній цикл буде виконуватись до тих пір, поки не досягне кінця файлу. Внутрішній цикл використовується для обробки символів в рядку. Стандартна функція EOLN визначає кінець поточного рядка. Внутрішній цикл виконується до тих пір, поки не будуть прочитані всі символи рядка. У внутрішньому циклі зчитують поточний символ із вхідного файлу в символьну змінну sim та записують його в вихідний файл. При цьому, якщо поточний символ =:, то наступний символ оцінка зчитується в цілочислену змінну с та сумується. В зовнішньому циклі Readln(f1) означає перехід на наступний рядок вхідного файлу, а Writeln(f2) - перехід на новий рядок в вихідному файлі. Після закінчення обробки всього файлу обчислюється середній бал і одержані результати виводяться в вихідний файл.
Приклад: Дано: Туре серія=Filе of real;
Описати функцію, яка підраховує суму від'ємних чисел елементів серії S.
program fa 1;
function summa:real;
type ser=file of real;
var s:ser;
a: array[1..10] of real;
sum: real; i: integer;
begin
assign(s, 'c: \text.txt');
rewrite (s);
writeln('введіть числа');
for i: =1 to 10 do
begin
read(a[i]);
write(s,a[i]);
end;
close(s);
reset(s);
sum: =0;
while not eof(s) do
begin
read(s,a[i]);
if a[i]<0 then sum: =sum+a[i];
end;
summa: =sum;
close(s);
end;
begin
write (summa: 3:1);
end.
ФАЙЛОВА СИСТЕМА.
Любий обмін даними припускає наявність джерела інформації, каналу передачі та її приймача. В випадку обміну даними між програмою та периферійними пристроями одним кінцем обміну даними завжди являється оперативна пам'ять машини, а другим кінцем в Паскалі завжди являється файл. Файлова система, що реалізується в Паскалі складається як би з двох рівнів: логічних файлів та фізичних. Логічний файл описується як змінна одного із файлових типів, визначених в ТР. Після того, як в програмі в розділі опису змінних об'явлена файлова змінна, вона може бути використана як засіб звернення до любого фізичного файлу. Саме ім'я фізичного файлу може з'явитися в програмі тільки один раз, коли спеціальною процедурою встановлюється, що об’явлений логічний файл буде служити засобом доступу тільки до цього фізичного файлу.
Наприклад, якщо ми хочемо працювати з текстовим файлом Text.doc, то в програмі повинні бути наступні рядки:
{об'являємо файлову змінну f, вводимо логічний файл типу text}
Var f:text;
Begin
Assign(f, 'c:\text.doc');
{ця процедура зв'язує фізичний файл text.doc на диску С: з логічним файлом f}
end;
Після цього всі звернення до файлу на диску будуть виконуватися через файлову змінну f. Логічні файли уніфіцирують роботу з файлами, дозволяючи працювати не безпосередньо з пристроями машини, а з їх логічними позначеннями.
ФІЗИЧНІ ФАЙЛИ.
Все що являється файлом в MS-DOS являється фізичним файлом в ТР. Визначається фізичний файл рядком з його ім'ям. Імена можуть бути рядковими константами або зберігатися у рядкових змінних. Ім'я файлу на диску може мати адресну частину. ‘С: \PAS\Test.PAS’
Інший різновид фізичних файлів - це пристрої MS-DOS. MS-DOS не робить особливих відмінностей між традиційними файлами та пристроями. Пристрої мають свої фіксовані імена і багато в чому схожі з файлами. Ім'я пристрою, наприклад, може стати на місце імені файлу на диску при копіюванні.
Фізичні файли - це пристрої організовані як текстові файли. Для нормальної роботи їх треба зв'язати з текстовими логічними файлами. Не визначена така структура даних, як файл файлів в пам’яті. Будь-який об’явлений
логічний файл має зміст тільки після встановлення зв'язку з зовнішнім фізичним файлом. З файловою системою зв'язано поняття буферу введення-виведення. Буфер - це область пам'яті, що відводиться при відкритті файлу. При запису у файл вся інформація спочатку направляється в буфер і там накопичується до тих пір, поки весь об'єм буферу не буде заповнено. Тільки після цього або після спеціальної команди скидання буферу здійснюється передача даних по призначенню на диск або у порт. Аналогічно при читанні із файлу зчитується не стільки, скільки запитується, а скільки поміститься в буфері. Механізм буферізації дозволяє більш швидко та ефективно обмінюватися інформацією з різними пристроями. Для текстових і безтипових файлів можна встановлювати розмір буферу на свій розсуд.
ФАЙЛОВІ ТИПИ.
Турбо Паскаль підтримує три файлових типи:
1. Текстовий; (тип text)
2. Компонентний (типу file of):
3. Безтиповий (типу file)
Текстові файли — це файли, що складаються з кодів ASCII, виключаючи розширені та керуючі коди. Ці файли організуються рядками і обов'язково містять кінець файлу.
Компонентні файли на відміну від текстових складаються з машинних представлень чисел, символів та структур, з них побудованих. Вони зберігають дані в тому самому вигляді, що і пам'ять ЕОМ. Тому засобами компонентних файлів можна здійснювати обмін даними тільки між дисками і робочою пам’яттю програми, але не можна, наприклад, напряму вивести дані на екран.
Безтипові файли також складаються з машинних представлень даних. Відрізняються від компонентних файлів тим, що компонентні мають справу тільки з даними раніше об'явленого типу, а безтипові - з довільними наборами байтів незалежно від їх структури та природи. Опис мови визначає безтиповий файл як низькорівневий канал введення-виведення для доступу до любих файлів з любим типом.
Принцип роботи з файлами один, хоч і є різниця у наборах команд для роботи з різними файловими типами. Для всіх без виключення файлів необхідне попереднє зв'язування їх файлових змінних з фізичними файлами.
Файлові змінні, описані у програмі, не можуть брати участь в операторі присвоєння. При використанні файлових змінних любого типу в якості формальних параметрів заголовків процедури та функції вони завжди повинні бути описані як Var-параметри.
В ТР є ряд стандартних процедур для роботи з файлами любих типів. Також в ТР не визначено звернення до буферної змінної. Розглянемо процедури та функції, які відносяться до всіх типів файлів.
1. Assign (Var f; FileName:String);- ця процедура встановлює зв'язок між логічним файлом, який описується файловою змінною f любого файлового типу і конкретним файлом MS-DOS, назва якого міститься у рядковому параметрі FileName. Рядок FileName може містити ім'я файлу на диску (в тому числі і повне ім'я файлу), ім'я стандартного пристрою MS-DOS (CON, PRN) або пустий рядок. Ім'я фізичного файлу повинно бути коректним і унікальним, не можна вставляти символи шаблонів (‘*’ ‘?’) в ім'я файлу. Сама процедура Assign не займається аналізом коректності імені файлу і безперечно зв'язує дане ім'я з логічним файлом f. Логічний файл при цьому вважається закритим, а розмір буферу не визначеним (якщо файл f зв'язаний з некоректним ім'ям, то це викличе помилку введення-виведення тільки при спробі виконати любу дію : відкрити файл або вилучити його). Будучи колись встановленим, зв'язок між файловою змінною f та фізичним файлом зберігається до наступного виклику Assign. Після того, як логічний файл зв'язаний з фізичним, його можна відкривати для читання та запису:
Reset(var f);- для читання
Rewrite(var f); - для запису.
Повторний виклик Reset повторить послідовність читання знову на самий перший елемент файлу, при цьому втрата даних виключена. А повторне звернення до Rewrite зітре поточний зміст файлу, та налагодить файл до заповнення з першого елементу.
2.Close (Var f); - закриває відкритий до цього логічний файл f. Спроба закрити вже закритий файл або невідкритий файл викликає збій програми (якщо ж програма перервалася через помилку і до закриття файлу, то він все ж таки буде створений на носії, але вміст останнього буферу не буде перенесено у файл).
3.Rename (Var f; NewName: string); - перейменування файлів. Перейменування файлів дозволяє перейменовувати фізичні файли на диску, зв'язані з логічним файлом f. Перейменування виконується тільки з закритим файлом, в протилежному випадку виникає збій. Після даної процедури можна знову відкривати файл, але f буде зв'язана вже з новим ім'ям. Неможна змінювати ім'я, змінюючи ім'я диску та шлях до файлу.
Наприклад:
Assign(Var f; 'A: \file. ааа ');
Rename(Var f; 'C:\file.bbb');
В другому операторі помилка, так як крім імені файлу змінюється і диск
на якому він знаходиться (перенесення не визначено в мові, це треба
конструювати засобами ТР).
4.Erase (Vаr f); - вилучення файлів. Ця процедура знищує фізичний файл на диску. Файлова змінна повинна бути попередньо зв'язана з існуючим фізичним файлом. Сам файл до моменту виклику Erase повинен бути закритим.
Приклад:
Assign(Var f; FileName);
Erase(Var f);
Якщо файла з ім'ям FileName не існує, то виникає збій при спробі знищити його. До процедур, які відносяться до файлів любих типів, входить логічна функція:
EOF(Var f):Boolean;
Вона повертає значення True, коли при читанні досягнутий кінець файлу. У всіх останніх випадках вона повертає значення False. Стан EOF відновлюється автоматично при кожному зверненні до процедури. Файл f при цьому повинен бути відкритим.
ТЕКСТОВІ ФАЙЛИ.
Текстові файли — це файли, в яких:
- Інформація представляється в текстовому вигляді (символи в коді ASCII);
- Порції інформації можуть поділятися на рядки. Признаком кінця
рядку є символ з кодом #13. Він може бути об'єднаний з символом переводу рядку #10;
- Кінець файлу позначається явно символом ^Z(#26);
- При записі чисел, рядків та логічних позначень вони перетворюються в символьний (текстовий) вигляд;
- При читанні чисел або рядків вони автоматично перетворюються з
текстового представлення в машинне.
Реально файл зберігається як суцільна послідовність символів і розбивається на рядки лише при його виведенні на екран або друк. Порожній текстовий файл містить лише один символ #26. Для роботи з текстовим файлом необхідно визначити файлову змінну Var f:text; , зв'язати її з фізичним файлом стандартною процедурою Assign, після чого файл можна відкривати.
В системній бібліотеці ТР визначені дві текстові змінні: Input та Output. Вони зв'язані з пристроєм 'CON' (клавіатура та екран : введення в 'CON'-це читання з клавіатури, а запис в 'CON' - це запис на екран) автоматично. Якщо в процедурі введення опущено ім'я файлу, то вважається, що введення йде із системного файлу Input (з клавіатури), а якщо ім'я файлу опущено в операторі виведення, то в файл Output (на екран).
Текст - орієнтовані процедури та функції.
Є ряд процедур та функцій, які крім стандартних, працюють тільки з
текстовими файлами:
1. SetTextBuf(Var f:text; VarBuf [;BufSize:word]) ;
Де f - файлова змінна типу text; Виf - люба змінна;
BufSize - необов'язкова змінна типу word. Процедура SetTextBuf служить для збільшення або зменшення буфера введення-виведення текстового файлу. Автоматично значення розміру буфера для текстового файлу рівне 128 байтів.
Якщо є необхідність часто звертатися до фізичних файлів на диску, то рекомендується збільшити це число до декількох Кбайт, що значно прискорить процес (і не так жорстко будуть експлуатуватися головки диску).
Збільшення буферу логічного файлу повинно відбуватися після зв'язування логічного файлу з фізичним, але до першої операції введення-виведення. Бажано змінювати буфер до відкриття файлу. Це дасть гарантію безпеки даних.
Задаючи новий буфер необхідно передати процедурі SetTextBuf не тільки логічний файл, але і змінну Buf, в якій буфер знаходиться. Тип змінної Buf не має значення. Важливий її розмір.
Буфер файлу починається з першого байту відведеного Buf і займає стільки байт скільки задано у необов'язковому параметрі BufSize.
Якщо при виклику процедури число BufSize не вказано, то вважається, що воно дорівнює розміру змінної Ви£
Задання BufSize більше ніж розмір самої Buf приведено до втрати даних суміжних по пам'яті з Buf.
Будучи встановленим одного разу для файлу, буфер не змінює свого місця і розміру до наступного виконання SetTextBuf або Assign з тією, ж файловою змінною.
Змінна, що виділяється під буфер, повинна бути глобальною, або, існувати до кінця роботи з даним файлом.
Приклад: невірно заданий буфер.
Procedure TK(var f:text);
Var Buffer:array[1..16*1024] of Byte; (1)
FileName: Siring;
Begin
Readln(FileName);
Assign(var f; FileName);
SetTextBuf(var f, Buffer);
Rewrite(var f);
End;
Var ff:text;
Begin
TK(ff);
Write (ff,....);
.
.
.
{неважливо, що далі, тому що результат буде невірним)
end.
Невірно описаний рядок (1) : використовується локальна змінна, яка потім передається в процедуру. Справа в тому, що локальна змінна Buffer (зокрема в ній розміщується буфер файлу, який відкривається), існує лише під час виконання процедури. Після закінчення роботи процедури вона зникає. Область буферу стає недоступною і швидко заповнюється зовсім сторонніми значеннями, а переданий файл f, який викликається (ff) буде поводити себе непередбачувано. При всьому цьому не виникає ні помилки при компіляції, ні помилки під час підрахунку.
Якщо розмістити буфер в статичній змінній, то він з'їдає частину області даних або стеку, а він обмежений розміром 64 (Кбайта). Вигідно було б розмістити буфер в динамічній пам'яті (кучі), для цього потрібно оголосити вказівник на місце буфера в кучі.
Приклад:
Var ft: text;
Pbuf :pointer; {ссилка на буфер}
Const BufSize=1024; {розмір буферу}
Веgіп
Assign (ft, 'Text.doc');
GetMem(Pbuf,BufSize); {в пам 'яті відводиться блок, розмір
якого=буферу} {1}
SetTextBuf(ft,Pbuf ^,ВиfSize); {2}
{задається буфер в динамічній області}
Reset(ft);
.
.
.
Close(ft);
FreeMem(Pbuf,BufSize); {буфер видаляється з пам'яті} {3} End.
1. В пам'яті відводиться блок розміром з буфер.
2. Задається буфер в динамічній пам'яті.
3. Буфер видаляється із пам'яті, тобто звільняє місце. В цьому прикладі потрібно відводити і звільняти пам'ять під буфер, а в процедурі SetTextBuf обов'язково вказувати його розмір, так як блок пам'яті спочатку в Pbuf не знає свого розміру. (Рекомендується обирати розмір буферу кратним 512 байтам)
2. Append (Var f: text);
Ця процедура служить для спеціального відкриття файлу для дозапису. Вона використовується тільки до вже існуючих фізичних файлів, і відкриває їх для дозапису, тобто файл не знищується, так як при виклиці Rewrite, a готується до запису елементу в кінець файлу.
Якщо Append застосовується до неіснуючого файлу, то виникає помилка лічби часу. Новий файл може бути створений тільки процедурою Rewrite. Після відкриття файлу процедурою Append запис в нього буде здійснюватися з того місця, де знаходився признак кінця файлу (#26). При необхідності змінити текстовий буфер потрібно зробити це до відкриття файлу процедурою Append. Взагалі ця процедура нічим не відрізняється від Rewrite, крім способу відкриття файлу з кінця.
3. Flush (Var f: text);
Вона застосовується тільки для текстових файлів, відкритих для запису. Дані для запису накопичуються в буфері файлу, і тільки після повного його заповнення записуються в фізичний файл.
Процедура Flush примусово записує дані із буфера в файл, незалежно від ступеня його заповнення. Коли буфер має велику ємність, його зміст може не попасти в фізичний файл, якщо програма раптово перерветься в процесі читання. Цього можна недопустити, якщо перед аварійними частинами програми ставити виклик Flush.
Дана процедура не закриває файл і не впливає на послідовність виведення. Flush може знайти застосування при роботі зі стандартними файлами MS-DOS, зокрема з пристроями друку або паралельними і послідовними портами. При роботі з ними даним не має потреби залишатися в буфері, а процедура Flush, поставлена після write, знімає ефект затримки буферу файлу.
4. EOLN(Var f: text): Boolean;
Ця функція аналізує поточне положення в текстовому файлі, відкритому для читання. EOLN повертає значення True, якщо наступною операцією буде прочитаний признак кінця рядка #13, або кінець файлу #26. False дана функція видає в усіх інших випадках. Функція ніби відчуває результат наступного читання та аналізує його. Необхідність в EOLN виникає всякий раз, коли зарані невідомо, де зустрінеться кінець рядка.
Приклад: Хай є файл DT.DAT з стовпчиками цифр:
12.3 15.6 7.5 6.1 15.0 #13 #10
17.6 16.9 5.8 100 98.19 #13 #10
53.4 0.0
#26
Як автоматично визначити число стовпчиків в ньому і налагодити читання за допомогою EOLN.
Program рr;
Var f: text; {логічний текстовий файл}
Kol: integer; {лічильник кількості стовпчиків}
A: real;
Begin
Assign(Var f; 'DT.DAT');
Reset(f);
Kol:=0;
While not EOLN (f) do begin
Read(f,a); {читання вправо по рядку} Inc(kol); {збільшити на 1 кіл-ть стовпчиків} End;
Reset(f); {повернення на одну позицію у файлі}
.
.
.
Close(f);
End.
Є різновид EOLN без параметрів, В цьому випадку вважається, що дія її відноситься до стандартного файлу INPUT, тобто введення з клавіатури. Тут функція EOLN повертає True не перед, а після проходження признаку кінця рядка: зразу після натиснення клавіші Enter. Більш того від EOLN без параметрів важко дочекатися значення False. Вона підвішує програму і повертає управління наступному оператору тільки після того, як натиснена клавіша введення (Enter). В мові Pascal є спосіб організувати паузу до натискання введення, а саме Write (EOLN).
5.SeekEOLN (Var f:text): boolean;
Ця функція є найближчою родичкою EOLN. Файл f повинен бути текстовим і відкритим для читання. Функція повертає значення True, якщо до кінця рядку (#13) або кінця файлу (#26) можуть бути зчитані тільки проміжки (#32) або символи табуляції (#9). Значення True повернеться також в тому випадку, коли поточне значення в файлі безпосередньо передує символам #13#26. На відміну від EOLN дана функція ніби бачить кінець рядка, або файла через проміжки або знаки табуляції. SeekEOLN орієнтована головним чином на роботу з текстовими файлами чисел.
6.SeekEOF(Var f:text): boolean;
Для даної функції символи кодів #9 #13 #32 є прозорими, і якщо крізь них видно кінець файлу #26, то функція повертає значення True, у всіх інших випадках повернеться значення False. Функція дозволяє знайти змістовий кінець файлу, а не фізичний. Це корисно при роботі з числами (рідше з символами):
While Not ЕОF(f) do
Read(f,a);
Цей цикл зупиниться тільки після повного виснаження файлу, навіть коли останні 1024 рядки були пусті. Якщо ж цей цикл переписати так,
While Not SeekEof(f) do
Read(f,a);
то він буде працювати більш ефективно.
Функція SeekEOF може бути застосована тільки для відкритих текстових файлів.