Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ООП (8.РАБОТА С ФАЙЛАМИ) у оп.doc
Скачиваний:
2
Добавлен:
11.11.2019
Размер:
139.26 Кб
Скачать

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;

Введення/вивід з використанням функцій Windows API

У Win32 файл відкривається за допомогою функції:

function CreateFile;

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

СreateFile використовується для відкриття файлів на диску, пристроїв, каналів, портів і взагалі будь-яких джерел введення/виводу.

Закривається файл в Win32 функцією closeHandle.

Для читання і запису даних в Win32 використовуються функції:

function ReadFile

function WriteFile

Відкладене (асинхронний) введення/вивід

Ця принципово нова можливість введена вперше в Win32 з появою реальної багатозадачності. Викликаючи функції читання і запису даних, ви насправді передаєте початкові дані одному з потоків (threads) операційної системи, який і здійснює фактичні обов'язки по роботі з пристроєм. Час доступу всіх периферійних пристроїв значно більше доступу до ОЗУ, і ваша програма, Read, що викликала, або write, чекатиме закінчення операції введення/виводу. Уповільнення роботи програми в наявності.

Контроль помилок введення/виводу

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

Контроль за помилками введення/виводу залежить від вживаних функцій. При використанні доступу через Win32 API всі функції повертають код помилки Windows, який і потрібно проаналізувати.

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

  • {$I+} контроль включений (встановлений за умовчанням); 

  • {$I-} — контроль відключений.

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

  •  2 — файл не знайдений;

  •  3 — невірне ім'я файлу;

  •  4 — дуже багато відкритих файлів;

  •  5 — доступ заборонений;

  •  100 — досягнутий кінець файлу;

  •  101 — диск переповнений;

  •  106 — помилка введення.

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

function lOResult: Integer;

яка повертає значення 0 за відсутності помилок.

Атрибути файлу. Пошук файлу

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

Безпосередньо для пошуку файлів використовуються функції FindFirst і FindNext.

Функція

function FindFirst(const Path: string; Attr: Integer; var F: TSearchRec): Integer;

знаходить перший файл, заданий повним маршрутом Path і параметрами Attr Властивість Attr може містити комбінацію наступних прапорів-значень:

  •  faReadOnly — тільки для читання;

  •  faDirectory — каталог;

  •  faHidden — прихований; 

  •  faArchive — архівний;

  •  faSysFile — системний; 

  •  faAnyFile — будь-який.

Якщо заданий файл знайдений, функція повертає 0, інакше — код помилки Windows. Параметри знайденого файлу повертаються в записи F типу TSearchRec.

Функція

function FindNext(var F: TSearchRec): Integer;

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

Для звільнення ресурсів, виділених для виконання пошуку, застосовується функція:

procedure FindClose(var F: TSearchRec);

Потоки

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

Потоки — дуже вдалий засіб для уніфікації введення/виводу для різних носіїв. Потоками є спеціальні об'єкти-спадкоємці абстрактного класу Tstream. Сам Tstream "уміє" відкриватися, читати, писати, змінювати поточне положення і закриватися. Оскільки для різних носіїв ці речі відбуваються по-різному, конкретні аспекти реалізовані в його нащадках. Найчастіше використовуються потоки для роботи з файлами на диску і пам'яттю.

Багато класів VCL мають уніфіковані методи LoadFromstream і saveTostream, які забезпечують обмін даними з потоками. Від того, з яким фізичним носієм працює потік, залежить місце зберігання даних.

Базові класи TStream і THandleStream

У основі ієрархії класів потоків лежить клас TStream. Він забезпечує виконання основних операцій потоку безвідносно до реального носія інформації. Основними з них є читання і запис даних.

Клас TStream породжений безпосередньо від класу TObject.

Потоки також грають важливу роль в читанні/записі компонентів з файлів ресурсів (DFM). Велика група методів забезпечує взаємодію компоненту і потоку, читання властивостей компоненту з ресурсу і запис значень властивостей в ресурс.

Таблиця 3. Властивості і методи класу Tstream

Оголошення

Опис

property Position: Longint;

Визначає поточну позицію в потоці

property Size: Longint;

Визначає розмір потоку в байтах

Отже, в основі операцій прочитування і запису даних в потоці лежать методи Read і Write. Саме вони викликаються для реального виконання операції усередині методів ReadBuffer І WriteBuffer, ReadComponent І WriteComponent. Оскільки клас TStream є абстрактним, то методи Read і Write також є абстрактними.

Для створення потоку використовується конструктор

constructor Create(AHandle: Integer);

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

property Handle: Integer;

 Клас TFileStream

Клас TFileStream дозволяє створити потік для роботи з файлами. При цьому потік працює з файлом без урахування типу що зберігаються в нім даних (див. вищий).

Повне ім'я файлу задається в параметрі FileName при створенні потоку:

constructor Createfconst FileName: string; Mode: Word);

Параметр Mode визначає режим роботи з файлом. Він складається з прапорів режиму відкриття:

  •  fmCreate — файл створюється;

  •  fmOpenRead — файл відкривається для читання;

  •  fmOpenWrite — файл відкривається для запису;

  •  fmOpenReadWrite — файл відкривається для читання і запису.

Клас TMemoryStream

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

Властивість

property Memory: Pointer;

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

procedure SetSize(NewSize: Longint); override;

Для очищення пам'яті потоку використовується метод

procedure Clear;

Читання/запис даних в пам'ять виконується звичними методами Read і Write.

Також запис даних в пам'ять може здійснюватися методами:

  • procedure LoadFromFile(const FileName: string); — з файлу;

  • procedure LoadFromStream(Stream: TStream); — з іншого потоку.

Додатково можна використовувати методи запису даних у файл або потік:

procedure SaveToFile(const FileName: string);

procedure SaveToStream(Stream: TStream);

 Клас TStringStream

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

Він володіє стандартним для потоків набором властивостей і методів, додаючи до них ще декілька, що спрощують використання рядків.

Властивість тільки для читання

property DataString: string;

забезпечує доступ до рядка, що зберігається.

Методи

function Read(var Buffer; Count: Longint): Longint; override;

і

function Write(const Buffer; Count: Longint): Longint; override;

реалізують звичайний для потоків спосіб читання і запису рядка для довільної змінної Buffer.

Метод

function ReadString(Count: Longint): string;

забезпечує читання count байтів рядка потоку, починаючи з поточної позиції.

Метод

procedure WriteString(const AString: string);

дописує до рядка рядок AString, починаючи з поточної позиції.

При роботі з файлами і потоками використовуються додаткові класи виняткових ситуацій.

Контрольні запитання