Файл - це послідовна структура даних. Природнім способом доступу до
компонентів файлу є послідовний доступ. Якщо потрібно прочитати з
файлу 6-й елемент і записати його в змінну V відповідного типу, то це
можна зробити прочитавши впусту п'ять перших елементів.
Assign(f, 'xx.dat');
Reset(f);
For і: =1 to 6 do
Read(f,v);
Reset(f); {установка знову на 1 елемент)
В V залишається лише останнє, 6-те значення із файлу. Це, звичайно, не саме вдале рішення. Набагато краще буде використовувати вбудовані процедури та функції для прямого доступу до компонентів файлу. Розглянемо їх.
1 FileSize(Var f) :LongInt;
Функція повертає число записаних компонентів або блоків в відкритому файлі f. Для порожнього файлу вона дорівнює 0.
2 FilePos(Var f):LongInt;
Повертає номер запису компоненту чи блоку в відкритому файлі f, який передує тому, що буде зчитаний чи записаний наступною операцією введення-виведення. Якщо він щойно відкрився, то поточною операцією буде границя з номером 0. Це значить, що можна прочитати (або записати) запис з реальним номером. Після цього позиція переміститься на границю 1 і наступною можливо буде прочитати запис (1+1=2).
….
0 1 2 3 n-1
Після читання останнього запису в файлі з реальним п, позиція співпаде з
границею з таким же номером п.
Далі записів немає, тому якщо FilePos повернуло значення, яке дорівнює
FileSize, то ми знаходимось в кінці файлу за останнім записом.
Таким чином, спочатку функція повертає 0, а в кінці повертає число, що
дорівнює реальній кількості записів в файлі. В решті випадків функція
повертає значення, на одиницю менше реального номеру запису (в ТР
своєрідна нумерація. Нумеруються не записи, а якби границі між ними.
Ці границі - це чиста умовність і в реальному файлі записи йдуть підряд).
З Seek(Var f; N:LongInt);
Вона встановлює поточним компонентом в відкритому файлі f компонент
з номером N, порахований від 0. Призначений компонент буде зчитаний
або записаний останньою операцією введення-виведення. Дана операція
безпосередньо реалізує прямий доступ до файлу f.
Файл повинен бути відкритим, а в параметрі N повинен задаватись номер
умовної границі між записами. Щоб працювати з записом, що має
реальний номер 3, потрібно задати позицію на границі перед ним, тобто на границі з номером 2 (N=3-1=2). Щоб прочитати або записати перший запис, треба задати N=0.
Seek(f,0);
де 0 - номер границі перед першим записом. В випадку, коли необхідно, щоб позиція мала номер останньої границі (а він співпадає з числом записів на останній момент часу), необхідно скористатися наступним викликом: Seek(f,File,Size(f));
Доступ до останнього запису в файлі Seek(f,FileSize(f)-l); Правила призначення позиції процедурою Seek такі ж, як і правила обчислення FilePos, тільки направлені на зміну позицій, а не на її аналіз.
Приклад:Дано файл, поміняти місцями першу і останню компоненти.
Program рr;
const st=string[11*3]= 'AAA—ВВВ—ССС— (зміст масивів являє собою
DDD—EEE—FFF’; рядок довжиною 11x3}
Type ml=array[l. .3] of char; {тип компонент, файлу}
Var f:file of m1; {компонентний файл}
Ff:file; {безтиповий файл}
masl,mas2:ml; { масиви}
d1:LongInt; {довжина файлу}
Pocedure nick; (1 процедура для створення файлу із 11 масивів типу т1}
Begin
Assign (ff, 'xxd.dat');
Rewrite(ff, 3);
BlockWrite(ff,st[1],11);
Close(ff);
End;
Procedure zam; {II процедура — завантажує масив після
Begin модифікації прямим доступом} Assign(ff, 'xxd.dat');
Reset(ff,3);
BlockRead(ff,st[1],11);
Close(ff);
End;
Begin
Writeln('введіть початкове значення файлу', st);
Nick;
Assign(f,’ddd.dat');
Reset(f);
D1:=filesize(f); {запом 'ятовує довжину файла)
If DI < 2 then Begin
Write(‘Mалo записів у файлі');
Halt;
End else
Read(f,masl); {зчитує І мас. у файл}
Seek(f,D1-l); {перехід до останнього запису)
Read(f,mas2); (зчитується II масив}
Seek(f,FilePos(f)-l); {назад на один запис}
Rewrite (f);
Write (f,mas 1); {І масив заміняє останній.}
Seek(f,0); {перехід на початок файлу}
Write(f,mas2); {останній масив заміщує перший}
Close(f);
Zam;
Write ('Підсумковий вміст файлу',st);
Readln;
End.
Необхідно пам'ятати, що процедури Write, Read, BlockWrite, BlockRead
при кожному виклику переміщують границі на число прочитаних
записів.
Виклик Seek зі значенням n>FileSize викличе помилку введення-
виведення.
4. Truncate(Var f);- відсікання. Дана процедура зв'язана з прямим
доступом в файл. Вона також зв'язана з процедурою позиціювання Seek.
Призначення процедури - обрізати хвости відкритим файлам f. Якщо
поточна позиція відповідає границі 2, то викликом Truncate) будуть
видалені всі записи, що йдуть за нею з реальними номерами 3,4 і так далі,
а сама границя 2 стане кінцевою.
Комбінація операторів:
Seek(f,0);
Truncate (Var f) ;
Зробить файл f, зовсім пустим, а границя 0 стане першою і останньою.
Після відсікання не можна відновити попередню довжину. Можна
трактувати дану процедуру як часткове стирання Erase. З текстовими
файлами дана процедура не працює.
5. IOResult: Integer;
Дана функція повергає ціле число, що відповідає коду останньої помилки
введення-виведення. Якщо ж операція введення-виведення пройшла
успішно, та функція поверне значення “0”. Опитати функцію IOResult
можна тільки один раз після кожної операції введення-виведення, тому що
вона обнуляє своє значення при кожному виклику. За допомогою неї
можливо писати програми, які ніколи не удають збоїв при введенні чи
виведенні даних або при роботі з файлами.
Приклад:Здійснюється режим дозапису в текстовий файл.
f- meкcm. файлова змінна.
Assign(f, 'B.FILE.TXT');
Append(f); {спроба відкриття файлу для дозапису}
If IOResult<>0
Then......{повідомлення}; else
Rewrite(f, ...); {створення файлу}
Write(f, ...); {робота з файлом}
…………….
Close(f);
end.
6. EOF(f)працює так: як тільки поточна позиція співпадає з кінцевою границею, то вона починає повертати-значенні TRUE. Весь останній час вона повертає значення FALSE.
Процедури прямого доступу застосовуються тільки до типізованих та
безтипових файлів. Прямий доступ дозволяє позиціонувати в середині
файлу вказівник на запис, що нас цікавить.
В випадку типізованих файлів, запис в файлі - це компонент файлу, а в
випадку безтипових файлів запис - це блок, рівний по розміру буферу
файлу.