|
Найважливіші
члени класів Filesysteminfo, Fileinfo і Directoryinfo
Клас Filesystemlnfo є
базовим для класів Directorylnfo і Filelnfo і містить велику частину їх
загальної функціональності. Перед нами хороший приклад тих можливостей, які відкриваються
при використанні абстрактних базових класів. У класі Directory Info
існує метод Getfilesystemlnfos, який повертає масив об'єктів Filesystemlnfо,
що представляють файли і підкаталоги заданого каталога. Таке
стає можливим тільки завдяки існуванню класу Filesystemlnfo. Найважливіші
члени базового класу Filesystemlnf про перераховані в таблиці. 9.4.
Таблиця
9.4.
Члени базового класу Filesysteminfo
|
|
|
|
|
|
|
|
|
|
|
|
|
Атрибути об'єкту.
Властивість доступна для читання і запису
|
|
|
|
Creationtime
(властивість)
|
Час створення
об'єкту. Властивість доступна для читання і запису
|
|
|
|
|
Логічна ознака існування файлу або
каталога
|
|
|
|
|
|
|
|
|
Повне ім'я каталога або файлу
|
|
|
Lastaccesstime (властивість)
|
Дата/час останнього звернення до об'єкту. Властивість
доступна для читання і запису
|
|
|
Lastwritetime (властивість)
|
Час останнього запису в об'єкт. Властивість доступна
для читання і запису
|
|
|
|
Для файлів — ім'я файлу. Для каталогів — ім'я
останнього каталога в ієрархії, якщо це можливо. Інакше повертається повне
ім'я
|
|
|
|
|
|
|
|
|
|
|
|
|
|
У таблиці. 9.5 і 9.6 перераховані найважливіші методи
класу Directoryinfo і методи класу Filelnfo, що не мають безпосереднього
відношення до потоків (ця тема розглядатиметься пізніше).
Таблиця 9.5.
Основні методи класу Directoryinfo
|
|
|
|
|
|
|
|
|
Exists
(властивість) |
Логічна
ознака існування каталога |
|
|
Name
(властивість) |
Ім'я
каталога |
|
|
Parent
(властивість) |
Об'єкт
Directoryinfo для батьківського каталога (для кореневих каталогів
повертається Nothing) |
|
|
Create |
Створює
каталог, шлях до якого вказаний в конструкторі Directoryinfo |
|
|
Createsubdirectory (Byval As String) |
Створює
підкаталог, шлях до якого передається у вигляді параметра. Повертає об'єкт
Directorylnfo для створеного підкаталогу |
|
|
Delete |
Видаляє
порожній каталог, представлений об'єктом Directorylnfo. Якщо привласнити
True необов'язковому логічному параметру, відбувається рекурсивне
видалення непорожнього каталога і всіх його підкаталогів |
|
|
Getdirectories |
Повертає
масив об'єктів Directorylnfo для підкаталогів поточного каталога |
|
|
Getfiles
|
Повертає масив об'єктів Filelnfo для файлів
поточного каталога |
|
|
Getfilesystemlnfos |
Хороший
приклад використання абстрактних класів: метод повертає масив об'єктів
Filesystemlnfo, що представляють всі файли і підкаталоги поточного
каталога |
|
|
Moveto(Byval destdirname As String) |
Переміщає
Directorylnfo і весь його вміст |
|
|
Root
(властивість) |
Об'єкт
Directoryilnfo для кореневого каталога в ієрархії поточного
каталога |
|
|
|
|
|
Таблиця 9.6.
Члени класу Filelnfo, що не повертають потоків
|
|
|
|
|
|
|
|
|
Directory
(властивість) |
Об'єкт
Directorylnfo для каталога, в якому знаходиться файл |
|
|
Directoryname (властивість) |
Повний шлях
до файлу в строковому вигляді |
|
|
Exists
(властивість) |
Логічна
ознака існування файлу |
|
|
Length
(властивість) |
Розмір
поточного файлу |
|
|
Copyto(Byval destfilename As
String) |
Копіює
існуючий файл і повертає об'єкт Filelnfo для копії. Необов'язковий
логічний параметр управляє перезаписом існуючих файлів |
|
|
Create |
Створює
файл по імені, вказаному при конструюванні об'єкту Filelnfo, і повертає
об'єкт Filesystem для нового файлу |
|
|
Delete |
Видаляє
файл, представлений об'єктом Fileinfo |
|
|
Moveto(Byval destfilename As String) |
Переміщає
файл |
|
|
|
|
|
Ідея виділення загальній функціональності в абстрактний
базовий клас виглядає впол-не логічно, проте в даному випадку вона реалізована
не кращим чином. Наприклад, свдйство Length присутній у файлі Fileinfo, але не
підтримується в Filesystemlnfo, тому для обчислення розміру дерева каталогів
доводиться удаватися до послуг іншого об'єкту — а саме викликати метод Size
об'єкту Folder, що входить в модель Filesystemobject. Ця модель вперше була
представлена в Vbscript, тому в рішення доводиться включати посилання на
бібліотеку сценарної підтримки на базі СОМ.
Потоки даних
Як згадувалося у вступній частині, одній з цілей
проектування класу System. I0.Stream було абстрагування примітивних операцій при
роботі з потокамі байтів. У відповідностей з цією концепцією кожна
конкретна реалізація класу Stream повинна надати свої версії наступних
методів:
- Read — метод читання даних з потоку. Іноді зводиться до
простого читання одного байта, але в багатьох похідних класах використовуються
складні методи для читання даних великими порціями.
- Write — метод запису даних в потік. Як і попередній метод,
може зводитися до простого запису одного байта, але може задіювати і фрагменти
даних більшого розміру.
Втім, цим можливості не обмежуються. Окрім простого
переміщення від першого байта до останнього реалізація класу Stream може
підтримувати і інші способи — наприклад, переміщення у зворотному напрямі або
безпосередній перехід до заданої позиції в потоці. Таке можливе для файлових
потоків, але не має сенсу (а отже, і не реалізується) для потоків, заснованих на
мережевих з'єднаннях. Властивість Canseek дозволяє дізнатися, чи підтримує потік
довільний доступ. Якщо властивість рівна True, значить, в похідному класі
підтримуються реалізації методів Seek і Setlength, а також властивостей Position
і Length.
У реалізації методу Seek зазвичай використовуються три
значення (Begin, Current і End), що входять в зручний перераховуваний тип
Seekorigin.
У таблиці. 9.7 перераховані основні методи
абстрактного класу Stream, сенс яких повинен зберегтися і в похідних класах.
Таблиця 9.7.
Основні методи класу Stream
|
|
|
|
|
|
|
|
|
|
Логічна ознака підтримки
читання
|
|
|
|
Логічна ознака підтримки довільного доступу
(позиціонування)
|
|
|
|
Логічна ознака підтримки
запису
|
|
|
|
|
|
|
|
Позиція в поточному потоці (тип Long). Властивість
доступна для читання, а в деяких потоках — і для запису
|
|
|
|
Закриває потік і звільняє використовувані ресурси
(наприклад, файлові маніпулятори операційної системи)
|
|
|
|
Записує дані і стирає вміст всіх буферів,
використовуваних потоком
|
|
|
Read(Byval buffer() As Byte, Byval offset As Integer,
Byval count As Integer)
|
Читає задану кількість байтів починаючи з поточної
позиції із збільшенням заданого зсуву offset. Повертає кількість успішно
прочитаних байтів
|
|
|
|
Читає окремий байт (чомусь у форматі Integer) в
поточній позиції потоку. Якщо поточна позиція знаходиться в кінці потоку,
повертає -1
|
|
|
Write(Byval buffer() As Byte, Byval offset As Integer,
Byval count As Integer)
|
Записує задану кількість байтів починаючи з поточної
позиції із збільшенням заданого зсуву offset
|
|
|
Writebyte(Byval value As Byte)
|
Записує байт в поточну позицію
потоку
|
|
|
|
|
|
Всі класи ієрархії Stream підтримують метод Close, що
звільняє утримувані ресурси операційної системи (наприклад, файлові маніпулятори
або мережеві з'єднання), тому практично у всіх програмах, що працюють з
потоками, рекомендується закривати потік в блоці Try-catch-final 1у. Врахуйте,
що виклик Close в секції Finally вимагає попередньої перевірки, оскільки цей
метод викликається лише для існуючих об'єктів потоків, створених успішним
викликом конструктора. Перевірка перед викликом Close в секції Final ly виглядає
приблизно так:
Finally
If Not
(myfilestream Is Nothing) Then myfilestream.Close()
End
Try
Розглянете і таку можливість, як реалізація
Idisposable в класах, що виконують операції з файлами, і закриття всіх відкритих
потоків методом Dispose.
Основні класи, похідні, від Stream перераховані в
таблиці. 9.8.
Таблиця 9.8.
Основні класи, похідні від Stream
|
|
|
|
|
|
|
|
|
Filestream
|
Довільний
доступ до файлів |
|
|
Memorystream |
Представляє
блок пам'яті (часто використовується при роботі з буферами) |
|
|
Networkstream |
Дані,
отримані у вигляді потоку по мережевому з'єднанню. Належить простору імен
System. Net. Sockets |
|
|
Cryptostream |
Шифровка і
розшифровка даних. Належить простору імен System. Security.
Cryptography |
|
|
Bufferedstream |
«Оболонка»
для підтримки буферизації в потоках, що не володіють цією можливістю (при
використанні дозволяє задати розмір буфера). Наприклад, автоматична
буферизація введення використовується у файлових потоках, але відсутній в
мережевих потоках. Якщо потрібно буде організувати буферизацію для
мережевого потоку, скористайтеся класом Bufferedstream і методикою,
описаною далі в цьому розділі |
|
|
|
|
|
У .NET Framework входять класи для роботи з XML,
спроектовані за зразком класу Stream. Втім, простори імен XML в .NET великі і
складні, і про них цілком можна було б написати окрему книгу.
Запис у файл
Почнемо з розгляду команди, що часто зустрічається
при роботі з файловими потоками:
Dim
myfilestream As New Filestream("Myfile.txt". Filemode.OpenOrCreate,
Fileaccess.Write)
Як видно з приведеного фрагмента, ця версія
конструктора Filestream отримує ім'я файлу (задане по відношенню до поточного
каталога, якщо не вказано повне ім'я) і два параметри, значення яких відносяться
до перераховуваних типів Filemode і Fileaccess відповідно. Таким чином, в нашому
прикладі конструктор Fi1estream або створює файл з ім'ям Myfile.txt у
поточному каталозі, або відкриває його, якщо файл з таким ім'ям вже існує. У
будь-якому випадку програма зможе записувати дані у файл. Часто зустрічаються і
інші конструктори класу Fi lestream:
- Sub New(String, Filemode): створює об'єкт Filestream із
заданим ім'ям і в заданому режимі (див. нижче опис Filemode).
- Sub Newcstring, Filemode, Fileaccess): створює об'єкт
Filestream в заданому режимі, із заданими правами читання/запису і сумісного
доступу.
Допустимими значеннями перераховуваного типу
Fileaccess є Read, Write і Readwri te. Основні значення перераховуваного типу Fi
I emode перераховано в таблиці. 9.9. Врахуйте, що деякі з них вимагають
особливих привілеїв для операцій з файлами.
Таблиця 9.9.
Значення перераховуваного типу Filemode
|
|
|
|
|
|
|
|
|
Append |
Відкрити
існуючий файл (або створити неіснуючий). Покажчик поточної позиції
переміщається в кінець файлу для запису. Використовується спільно з
Fileaccess.Write |
|
|
Create
|
Створити
новий файл. Увага — існуючий файл автоматично стирається! |
|
|
Createnew |
Створити
новий файл. Відрізняється від Create тим, що для існуючого файлу
ініціюється виключення Ioexception |
|
|
Open |
Відкрити
існуючий файл. Якщо файл не існує, ініціюється виключення Ioexception.
Використовується спільно з Fileiopermissionaccess.Read |
|
|
Openorcreate |
Відкрити
або створити файл |
|
|
Truncate |
Відкрити
існуючий файл, видалити поточний вміст |
|
|
|
|
|
Об'єкти Fhestream також повертаються наступними методами
класів File і Fhelnfo: File.Create, File.Open, File.OpenRead, File.OpenWrite,
Fheinfo.Create, Fhelnfo.Open, Fhelnfo.OpenRead.
Хоча файлові потоки підтримують довільний доступ
методом Seek, базовий класс-filestream орієнтований виключно на операції з
байтами, тому його можливості обмежуються простою записом байта або масиву
байтів методами Writebyte і Write. Приведений нижче фрагмент створює файл,
показаний на мал. 9.2:
Option
Strict On Imports System.IO
Module
Modulel
Sub
Main()
Dim i As
Integer
Dim
thebytes(255) As Byte
For i =
0 To 255
thebytes(i)= Cbyte(i)
Next
Dim
myfilestream As Filestream
Try
myfilestream = New Filestream("C:\foo"
Fi1emode.OpenOrCreate. Fileaccess.Write)
myfllestream.Write(thebytes, 0. 256) Finally
If Not
(myfilestream Is Nothing) Then
myfilestream.Close()
End
Try
Displayafile("C:\foo")
End
Sub
End
Module
Мал. 9.2. Запис двійкових
даних у файл
Після виконання цього фрагмента записані дані можна
прочитати методом Read, а також скористатися методом Seek для переходу до
довільної позиції у файлі. Втім, як це завжди буває при роботі з
неструктурованими потоками байтів, вам доведеться самостійно перетворити
двійкові дані в корисніший формат. В результаті зараз важко знайти змістовніший
приклад, ніж простий виведення записаних чисел процедурою, приведеною нижче:
Sub
Readdataback()
Dim
myfilestream As Stream.i As Integer Try
myfilestream = New Filestream("C:\foo"
Filemode.Open. Fileaccess.Read)
For i =
0 To 255
Console.Write(myfilestream.ReadByte) Next
Catch e
As Exception Msgbox(e.Message)
Finally
If Not
(myfilestream Is Nothing) Then
myfilestream.Close()
End
Try
End
Sub
Метод Length базового класу Stream завжди дозволяє
прочитати потрібну кількість байтів в циклі незалежно від структури файлу.
Наприклад, наступна процедура читає файл по одному байту. Виявлені виключення
просто передаються зухвалій стороні; ймовірно, в реальній програмі слід було б
визначити новий клас виключення:
Sub
Displayafile(Byval thefilename As String)
Dim
thefile As Filestream
Dim i As
Long Try
thefile
= New Filestream(thefilename.
Fi1emode.Open,Fi1eAccess.Read)
For i =
0 To (thefile.Length - 1)
'
Відняти 1. оскільки відлік починається з 0
Consolе.Write(thefiie.ReadByte) Next
Catch
Throw Finally
If Not
(thefile Is Nothing) Then thefile.Close()
End Try
End
Sub
Якщо файл має невеликі розміри і легко поміщається в
пам'яті, скористайтеся одним викликом Read і прочитайте весь файл в байтовий
масив потрібного розміру. Така операція виконується значно швидше.
Інший поширений варіант посимвольного читання
заснований на тому, що метод Readbyte в кінці потоку повертає -1. Основний цикл
виглядає приблизно так:
Dim i As
Integer i = thefile.ReadByte
Do Until
i =-1
Console.Write(i)
i =
thefile.ReadByte Loop
Читання/запис файлу на рівні окремих байтів
використовується не так вже часто; в основному це необхідно при виконанні
низькорівневих операцій. При операціях більш високого рівня часто
використовується стандартний прийом — неструктурований файловий потік
передається конструктору потоку, що володіє ширшими можливостями. Цей принцип
називається багаторівневою організацією потоків. Наприклад, неструктурований
файловий потік можна передати потоку, що автоматично розпізнає текст. Різні
способи багаторівневої організації потоків описані в декількох найближчих
розділах. Але перш, ніж переходити до цих розділів, проглянете таблицю. 9.10 — в
ній перераховані основні методи і властивості базового класу Filestream. Надалі
ми будемо іспользовать ці методи, хоча базовий файловий потік буде
прихований потоками вищих рівнів.
Таблиця 9.10.
Основні члени класу Rlestream
|
|
|
|
|
|
|
|
|
|
Файловий маніпулятор операційної системи для файлу,
інкапсульованого в об'єкті Filestream. Властивість доступна для читання
|
|
|
|
Розмір потоку в байтах. Властивість доступна для
читання
|
|
|
|
Уточнене ім'я, передане конструктору
Filestream
|
|
|
|
Поточна позиція для операцій читання або запису в
потоці (нумерація позицій починається з нуля). Властивість доступна для
читання і запису
|
|
|
|
Закриває потік і звільняє всі пов'язані з ним
ресурси
|
|
|
|
Пересилає всі дані з буфера в пристрій. Автоматично
викликається при виклику Close
|
|
|
Lock(Byval position As Long
|
Блокує доступ до всього файлу або його частини з боку
інших
процесів (нумерація позицій починається з нуля)
|
|
|
|
|
Read(Byval array() As Byte
|
Читає задану кількість байтів в масив з
файлового
потоку починаючи із заданої
позиції
|
|
|
|
|
|
|
|
Читає один байт з файлу і переміщає покажчик
поточної
позиції на один байт вперед
|
|
|
|
|
Seek(Byval offset As Long
Byval origin As Seekorigin)
|
Встановлює покажчик поточної позиції в потоці в
задане
|
|
|
|
|
Unlock(Byval position As Long
|
Знімає блокування з раніше заблокованої частини
файлу
(нумерація позицій починається з нуля)
|
|
|
|
|
Write(Byval array() As Byte
|
Записує задану кількість байт з масиву у
файловий
потік починаючи із заданої
позиції
|
|
|
|
|
|
|
|
Записує байт в поточну позицію файлового
потоку
|
|
|
|
|
|
|