Робота з файлами і каталогами

Клас TfileStream

9. Клас TMemoryStream

 

Файл - це набір даних на зовнішньому пристрої зберігання інформації. У Delphi файли можуть бути наступних типів:

1) текстові;

2) тіпізованні;

3) нетіпізованні.

Текстові файли

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

$0D - кінець рядка

$0А - переведення каретки або перехід в початок наступного рядка. У таких файлах кожна рядки може мати свою довжину. Такі файли називаються файлами з послідовним доступом. Читати їх можна тільки послідовно - рядок за рядком, а записувати нові рядки можна тільки в кінець файлу. Якщо провести запис нового рядка в середину файлу, то все подальші рядки будуть видалені з файлу.

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

Var F:Text;

Є спеціальні файлові змінні для текстових файлів - це Input і Output. Вони відповідають клавіатурі і дисплею. Тому, якщо в операторах введення не вказана файлова змінна, то за умовчанням вона відповідає Input, а при виводі - Output.

Розглянемо читання і запис. Для їх здійснення застосовуються спеціальні функції файлового введення/виводу.

Отже, для виконання операції читання або запису необхідно провести наступні дії:

1. Оголосити файлову змінну необхідного типу.

2. За допомогою функції AssignFile пов'язати цю змінну з необхідним файлом.

3.Відкрити файл за допомогою функцій Append, Reset, Rewrite.

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

5. Закрити файл за допомогою функції CloseFile.

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

· Procedure AssignFile(var F, FileName:String); - процедура призначення файловою змінною F шляху до файлу FileName. Ця процедура не може викликати помилку при виконанні програми, оскільки вона не перевіряє наявність вказаного файлу;

· Procedure Append(var F:Text); - процедура відкриття файлу на запис в кінець файлу. При цьому перевіряється наявність вказаного файлу, і якщо його немає, то виникає помилка введення-виводу. Якщо програміст хоче, щоб програма при цьому не переривала свою роботу, то він повинен узяти на себе обробку таких помилок або за допомогою оператора Try, або шляхом відключення стандартної обробки помилок введення-виводу за допомогою директиви транслятору {$1-}. Після цього можна за допомогою функції Function IOError:Integer; визначити код помилки і програму подальших дій. Включити стандартну обробку помилок введення-виводу можна директивою {$1+}. Слід пам'ятати, що функцію IOError можна використовувати для аналізу помилки тільки один раз. Повторний виклик цієї функції для однієї і тієї ж помилки введення-виводу вже не дасть коду помилки;

· Procedure ReWrite (var f: Text); - відкриття нового файлу на запис. При цьому, якщо вже існував такий файл, то він стане порожнім;

· Procedure Reset(var f: Text); - відкриття файлу на читання з його початку;

· Procedure Read(var f.Text; список змінних); - читання значень змінних з текстового файлу. При введенні строкових змінних з файлу читається стільки символів, скільки визначено в оголошенні рядка, або читання йде до кінця поточного рядка в текстовому файлі. Не слід в одному операторові введення читати числові змінні і строкові змінні упереміш;

· Procedure ReadLn(var f:Text; список змінних); - процедура читання рядка з текстового файлу з обов'язковим переходом в початок наступного рядка, навіть у разі наявності в рядку непрочитаних значень;

· Procedure Write(var f: Text; список виразів ); - вивід у файл значень списку виразів. Тут виразами можуть бути константи, змінні, числові вирази. Значення числових змінних при цьому переводяться в строкові значення, які і записуються у файл;

· Procedure WriteLn(var f:Text; список виразів); - ця процедура відрізняється від попередньої тільки тим, що після виведення значень обов'язково дописуються два символи - кінці рядка і переведення каретки;

· Procedure CloseFile(var f:Text); - процедура закриття файлу. При цьому відбувається фізичний запис з буфера обміну останніх даних і звільняється файлова змінна (її можна використовувати вже для іншого файлу). В кінці роботи програми відбувається автоматичне закриття всіх незакритих файлів;

· Function Eof(var f:Text):boolean; - функція перевірки на закінчення файлу. Вона повертає істину, якщо досягнутий кінець файлу;

· Function Eoln(var f:Text) -.boolean; - функція повертає істину, якщо досягнутий кінець рядка;

· Function SeekEoln(var f:Text):boolean; - функція перевірки поточного покажчика файлу на наявність кінця рядка. При цьому пропускаються пропуски і знаки табуляції (код $09);

· Function SeekEof(var f:Text):boolean; - функція перевірки поточного покажчика файлу на наявність кінця файлу. При цьому пропускаються пропуски і знаки табуляції;

· Procedure Flush(var f:Text); - процедура очищення буфера обміну з текстовим файлом і перенесення його вмісту безпосередньо на зовнішній пристрій. Це запобігає втраті інформації, наприклад, при зависанні комп'ютера або зникненні напруги в мережі.

Як приклад розглянемо невеликий фрагмент початкового коду.

...

var F: TextFile;

S: string;

begin

if OpenDlg.Execute

then AssignFiie(F, OpenDlg.FileName)

else Exit; Reset(F);

while Not EOF(F) do

begin

Readln(F, S);

Memo.Lines.Add(S);

end;

CloseFile(F);

end;

...

Якщо в діалозі відкриття файлу OpenDlg був вибраний файл, то його ім'я зв'язується з файловою змінною F за допомогою процедури AssignFiie. Як ім'я файлу рекомендується завжди передавати повне ім'я файлу (включаючи його маршрут). Якраз у такому вигляді повертають результат вибору файлу діалоги роботи з файлами TOpenDialog, TOpenPictureDiaiog. Потім за допомогою процедури Reset цей файл відкривається для читання і запису.

У циклі виконується читання з файлу текстових рядків і запис їх в компонент TMemo. Процедура Readin здійснює читання поточного рядка файлу і переходить на наступний рядок. Цикл виконується, поки функція EOF не повідомить про досягнення кінця файлу.

Після завершення читання файл закривається.

Такий же початковий код можна використовувати і для запису даних у файл. Необхідно тільки замінити процедуру читання на процедуру запису.

Тепер зупинимося докладніше на призначенні використовуваних для файлового введення/виводу функцій.

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

Процедура

procedure Reset(var F: File [; RecSize: Word ]);

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

Процедура

procedure Append(var F: Text);

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

Процедура

procedure Rewrite(var F: File [; RecSize: Word ]);

створює новий файл і відкриває його, поточна позиція встановлюється в початок файлу. Якщо файл з таким ім'ям вже існує, то він перезаписується. Змінна RecSize використовується тільки при роботі з файлами, що не типізуються, і визначає розмір одного запису для операції передачі даних. Якщо цей параметр опущений, то за умовчанням RecSize рівне 128 байт.

Типізовані файли

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

Type Tz=Record

Fio:String[40];

VozrByte;

End;

Var f:file of Tz;

В даному прикладі всі записи фала будуть однакової довжини 42 байт. У такому файлі можна читати і записувати записи в довільному порядку на відміну від текстових файлів. Попередньо розглянуті в параграфі процедури і функції можна застосовувати і для типізованих файлів, окрім тих, які закінчуються символами «In».

Процедура

procedure Seek(var F; N: Longint);

забезпечує зсув поточної позиції на N елементів. Розмір одного елементу в байтах залежить від типу даних файлу (від змінної, що типізується).

Розглянемо тепер режим блокового введення/виводу даних між файлом і областю адресного простору (буфером). Цей режим відрізняється значною швидкістю передачі даних, причому швидкість пропорційна розміру одного передаваного блоку — чим більше блок, тим більше швидкість.

Для реалізації цього режиму необхідно використовувати файлові змінні, що тільки не типізуються. Розмір блоку визначається в процедурі відкриття файлу (Reset, Rewrite). Безпосередньо для виконання операцій використовуються процедури BlockRead і BlockWrite.

Процедура Read має різне оголошення для текстових і типізованих файлів:

· procedure Read([var F: Text;] VI [, V2...,Vn]); - для текстових файлів;

· procedure Read(F, V1 [, V2...,Vn]); - для типізованих файлів.

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

Процедура

procedure Readln([ var F: Text; ] VI [, V2...,Vn ]);

прочитує один рядок текстового файлу і встановлює поточну позицію на наступному рядку. Якщо використовувати процедуру змінних vi. .vn, то вона просто пересуває поточну позицію на черговий рядок файлу.

Процедури для запису у файл write і writeln описані аналогічно:

procedure Write([var F: Text; ] PI [, P2..., Pn]);

procedure Writeln([ var F: Text; ] PI [, P2...,Pn ]);

Параметри P1, P2 ..., Pn можуть бути одним з цілих або речових типів, одним із строкових типів або логічним типом.

Для текстових файлів у функціях Read і write файлова змінна F може бути опущена. В цьому випадку читання і запис здійснюються в стандартні файли введення/виводу.

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

 

Розглянемо додаткові процедури і функції для роботи з типированными файлами:

· Procedure Seek(var f; n:LongInt); - переміщає поточний покажчик файлу в початок n-й запису. Записи тут нумеруються з нуля;

· Function FileSize(var f):LongInt; - повертає довжину файлу в записах;

· Function FilePos(var f):LongInt; - повертає номер поточного запису;

· Procedure Truncate(var J); - усікає файл з поточної позиції, тобто відсікаються всі записи, починаючи з поточного запису.

Нетипізовані файли

Файли без типу, нетипизовані файли, визначаються, наприклад оператором:

Var F:file;

Ці файли є файлами з прямим доступом і фіксованою довжиною одного блоку. Довжина одного блоку за умовчанням дорівнює 128 байтам.

При використанні блокового читання або запису розмір блоку необхідно вибирати так, щоб він був кратний розміру одного значення того типу, який зберігається у файлі. Наприклад, якщо у файлі зберігаються значення типу Double (8 байт), то розмір блоку може бути рівний 8, 16, 24, 32 і так далі Фрагмент початкового коду блокового читання при цьому виглядає таким чином:

...

var F: File;

DoubleArray: array [0..255] of Double;

Transfered: Integer;

begin

if OpenDlg.Execute then AssignFile(F, OpenDlg.FileName) else Exit;

Reset(F, 64);

BlockRead(F, DoubleArray, 32, Transferee!);

CloseFile(F);

ShowMessage('Лічене '+IntToStr(Transfered)+' блоків');

end;

...

Як видно з прикладу, розмір блоку встановлений в процедурі Reset і кратний розміру елементу масиву DoubleArray, в який прочитуються дані. У змінною Transfered повертається число лічених блоків. Якщо розмір файлу менше заданого в процедурі BlockRead числа блоків, помилка не виникає, а в змінною Transfered передається число реально лічених блоків.

Процедура

procedure BlockRead(var F: File; var Buf; Count: Integer

[; var AmtTransferred: Integer]);

Процедура

procedure BlockWrite(var f: File; var Buf; Count: Integer

[; var AmtTransferred: Integer]);

використовується аналогічно.

 

виконує запис блоку з файлу в буфер. Параметр F посилається на файлову змінну, що не типізується, пов'язану з потрібним файлом.

Параметр Buf визначає будь-яку змінну (число, рядок, масив, структуру), в яку читаються байти з файлу. Параметр Count містить число прочитуваних блоків. Нарешті, необов'язковий параметр AmtTransferred повертає число реально счи танных блоків.

Приведемо процедури і функції для роботи саме з такими файлами:

Procedure ReWrite(var f:file[;RecSize: word]); - відкриття нового файлу на запис, RecSize - довжина одного блоку в байтах;

Procedure Reset (var f:file [;RecSize:Word]); - відкриття файлу на читання, RecSize - довжина одного блоку в байтах;

Procedure BlockRead(var f:file; var Buf; Count:Integer[;var Result:Integer]); - читання блоків з файлу f і запис їх в буфер - Buf. Count - число блоків, які хочемо прочитати, Result - число блоків, реально прочитаних;

Procedure BlockWrite(var f:file; var Buf; Count:Integer [; var Result:Integer ]); - запис блоків у файл f з буфера Buf. Count - число блоків, які хочемо записати, Result - число блоків, реально записаних у файл;

Function FileSizefvar ffile)-.Integer; - повертає число записаних блоків у файлі f.

Робота з файлами і каталогами

Для роботи з файловою системою використовуються наступні функції і процедури:

Function DiskSize(Drive: Byte): Int64; - отримання розміру диска в байтах. Параметр Drive визначає номер дисковода: 0 - поточний дисковод, 1 - А, 2 -В і т.д.;

Function DiskFree(Drive: Byte): Int64; - отримання розміру вільної області на диску;

Procedure ChDir(const S: string); overload; - зміна поточної директорії, наприклад ChDir(‘ C:\My\);

Procedure RmDir(const S: string);overload; - видалення порожньої директорії;

Procedure MkDir (const S: string); overload; - створення нової піддиректорії;

Procedure GetDir(D: Byte; var S: string); - отримання поточної директорії на пристрої D;

Procedure Rename(var F; Newname: string); - перейменування файлу, пов'язаного з файловою змінною F, у файл з ім'ям Newname;

Procedure Erase(var F); - видалення закритого файлу, пов'язаного із змінній F;

Function DirectoryExists(const Directory: string): Boolean; - перевірка існування директорії. Якщо вона є, то функція повертає - True;

Function FileExists(const FileName: string): Boolean; - перевірка наявності на диску файлу з ім'ям FileName;

Function FileSearch(const Name, DirList: string): string; - пошук файлу Name в списку каталогів DirList;