|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Читання
і запис двійкових даних: класи Binaryreader і Binarywriter
Операції
читання і запису на рівні окремих байтів дуже примітивні, і користуватися
ними незручно. З цієї причини в .NET Framework передбачені набагато більш практичні
способи читання і запису даних у файлові потоки. У цьому розділі ми покажемо,
як використовувати класи Binaryreader і Binarywriter для читання і запису рядків
і примітивних типів даних. Ці класи автоматично перетворять примітивні
типи в двійковий формат, відповідний для збереження на диску або пересилки по
мережі. X Об'єкти Bi naryreader
і Binarywriter створюються за допомогою багаторівневого об'єднання
конструкторів потоків. Інакше кажучи, конструктору класу потоку болеї
високого рівня замість рядка передається існуючий об'єкт потоку. Приклад
приведений нижче (у рядку виділеної жирним шрифтом): Dim
afilestream As Filestream Try afilestream = New Filestream("c:\data.txt".FileMode.OpenOrCreate._ Fileaccess.Write) Dim mybinarywriter
As New Binarywriter(afilestream) mybinarywriter.Write("Hello
world") mybinarywriter.writed)
Catch e as Exception Console.Writeline(e.stacktrace)
Finally If not(afilestream is Nothing) Then afilestream.Close() End Try Конструктору
класу Bi narywriter передається об'єкт файлового потоку afilestream. Отриманий
в результаті потік володіє розширеними можливостями і підтримує запис
текстових і числових даних у файл в двійковому форматі. Приклад запису з використанням
класу Binarywriter: mybinarywriter.Write("Hello
world") mybinarywriter.wri ted) Робота цього фрагмента
заснована на перевантаженні методу Write в класі Bi narywriter, що дозволяє
легко записувати в потік будь-які базові типи даних. Нижче перераховані основні
переобтяжені версії: Sub Write(Byte) Sub Write(Byte()) Sub Write(Char) Sub Write(Char()) Sub Write(Decifnal) Sub Write(Double) Sub Write(Short) Sub Write(Integer) Sub Write(Long) Sub Write(Byte) Sub Write(Single) Sub Write(String) На мал. 9.3
показано, як створений файл виглядає в шістнадцятиричному редакторові. Як видно
з малюнка, рядок записаний у вигляді код окремих символів, але число кодується
чотирма байтами.
На жаль, хоча для запису в потік існують різні переобтяжені версії
методу Write, при читанні записаної інформації засобами класу Binaryreader
не існує аналогічних переобтяжених методів Read. Замість цього для кожного
типу даних визначається власна версія Read — Readstring, Readlnt32 (для
типу Integer), Readchar і так далі Ви повинні знати, що і в якому порядку було записано
у файл; інакше відновити початкові дані не вдасться. Наступний фрагмент
показує, як виконується читання в приведеному вище прикладі: afilestream = New Filestream("с:\data.txt", Filemode.Open. Fileaccess.Read) Dim mybinaryreader As New Binaryreader(afilestream) Console._ Writeline( mybinaryreader.ReadString) Console.WriteLine(mybinaryreader.Readlnt32)
Мал.
9.3. Файл, записаний
із застосуванням класу Binarywriter, в шістнадцятиричному уявленні
Якщо ви хочете
організувати узагальнене читання двійкових даних і вас не цікавить, якому типу
відповідають прочитані байти, скористайтеся методом Peekchar. Цей метод
перевіряє, чи рівний наступний байт -1 (ознака кінця файлу в .NET). Цикл виглядає
приблизно так: While mybinaryreader.PeekChar()
<> -1 '
Прочитати наступний байт Loop
Textreader,
Textwriter і похідні класи
Двійкові потоки
читання/запису добре підходять для випадків, коли програмістові точно відомий порядок
проходження даних в двійковому форматі, але прочитати отриманий файл буває непросто.
Таким чином, для зберігання звичайного тексту у файлі краще пошукати інший
варіант. У цій стандартній ситуації замість пари Binaryreader/binarywriter слід
використовувати пару Streamreader/streamwriter. По функціональних можливостях класи
Streamreader і Streamwriter близькі до традиційних засобів послідовного доступу
до файлів з колишніх версій VB (якщо не рахувати того, що в цих класах з'явилася
підтримка Unicode). У класі Streamreader окрім методу Read також є
зручний метод Readtoend, що дозволяє прочитати весь файл за одну операцію. Звернете
увагу, що ці класи оголошені похідними від абстрактних класів Textreader
і Textwriter, а не від Stream. Ці абстрактні класи, оголошені з атрибутом
Must Inherit, містять загальні засоби читання/запису тексту. Їх методи перераховані
в таблиці. 9.11 і 9.12. Таблиця
9.11.
Основні методи класу Textreader
Таблиця
9.12.
Основні методи класу Textwriter
Оскільки
класи Textreader і Textwriter є абстрактними, програми працюють з конкретними
реалізаціями Streamreader і Streamwriter. Як і у випадку з класами Binaryreader
і Binarywriter, при створенні об'єктів Streamreader і Streamwriter конструктору
зазвичай передається існуючий об'єкт потоку: myfile = New Filestreamtfilename.FileMode.Open, Fileaccess.Read) textfile= New
Streamreader(myfile) Для отримання
об'єкту також можна скористатися методами класу File. Приклад неявного створення
об'єкту Streamreader при створенні файлового потоку продемонстрований нижче: Dim astreamreader As Streamreader astreamreader
= File.OpenText ("sample.txt") Об'єкти класу
Streamwriter створюються аналогічним чином: Dim astreamwriter As Streamwriter astreamwriter
= File.CreateText ("test.txt") Дані записуються
в потік методами Write і Writeline. Що стосується читання, у вашому розпорядженні
два способи. У найбільш поширеному варіанті програма в циклі читає рядки
до тих пір, поки черговий прочитаний рядок не опиниться рівною Nothing. У
програмі це виглядає приблизно так: Dim s As
String Do s = thestreamreader.ReadLine
If Not s Is Nothing Then ' Виконати потрібні дії з s. ' Наприклад, викликати Console.WriteLine(s). End If Loop Untils Is
Nothing Також можна
скористатися методом Peek і перевірити, чи рівний наступний читаний символ
-1 (ознака кінця файлу): Do Until thestreamreader.Peek
= -1 Як приклад використання
класу Textreader нижче приводиться проста процедура, призначена для виведення
текстового файлу на екран. Звернете увагу: у рядках 5-17 весь важливий код
поміщений в блок Try-catch-finally. У цьому блоці програма намагається закрити відкритий
потік незалежно від того, що відбулося при операціях з ним. Як згадувалося
вищим, перед викликом Cl ose в рядку 16 спочатку необхідно переконатися в тому,
що потік був успішно створений. Також звернете увагу на те, як в рядку 14 до
виключення, що ініціюється, додається змістовне повідомлення. У реальній програмі
слід було б визначити новий клас виключення (за подробицями звертайтеся
до розділу 7). 1 Sub Displaytextfile(Byval
fname As String) 2 Dim
myfile As Filestream 3 Dim
textfile As Streamreader 4 Dim
stuff As String 5
Try 6 myfile = New
Filestream(fname.FileMode.Open, Fileaccess.Read) 7 textfile =
New Streamreader(myfile) 8 stuff = textfile.ReadLine() 9 Do
Until stuff Is Nothing 10 Console.WriteLine(stuff) 11 stuff = textfile.ReadLine() 12
Loop 13 Catch
e As Exception 14 Throw New
Exception("If the file existed.it was closed") 15
Finally 16 If Not (myfile Is
Nothing) Then myfile.Close() 17 End
Try 18 End
Sub 19 End Module У загальному випадку
окремі рядки файлу можна зберегти в динамічному масиві Arraylist (якщо,
звичайно, кількість рядків відносно невелика). Для цього досить внести
мінімальні зміни до попередньої програми. У заголовок процедури додається
новий параметр: Sub Displaytextfile(Byval fname As String,byval where As Arraylist) Рядок
10 приводиться до наступного вигляду: where, Add(stuff)
Об'єктні
потоки: збереження і відновлення об'єктів
Об'єктно-орієнтоване програмування навряд чи отримало б таке широке визнання, якби програміст
не міг зберегти об'єкт в поточному стані і відновити його пізніше. Запис
об'єкту в потік даних називається серіалізацией (serialization), а зворотний
процес називається десеріалізацией (deserialization). У декількох найближчих
розділах ми познайомимо читача з основними принципами серіалізациі і десеріалізациі. Але
перш, ніж переходити до розгляду нової теми, слід відмітити, що це складніша
і тонша проблема, ніж здається на перший погляд. Чому? Одна з причин полягає
в тому, що об'єкт може містити інші об'єкти (пригадаєте класи Manager і
Secretary з розділу 5). Отже, процес збереження повинен підтримувати
рекурсивне збереження внутрішніх об'єктів. Більш того, при цьому необхідно
поклопотатися про відсутність дублювання. Якщо на 100 програмістів у відділі
доводиться одна секретарка, було б небажано зберігати дані секретарки
в 100 екземплярах, коли цілком достатньо одного екземпляра з відповідним
налаштуванням посилань (щось схоже відбувається при приведенні баз даних до нормальної
форми з виключенням надмірних даних). На щастя,
в .NET Framework збереження об'єктів не вимагає особливих зусиль з боку програміста.
Як буде незабаром показано, об'єкти можна зберігати навіть в зрозумілому для людини
форматі SOAP (Simple Object Access Protocol), заснованому на мові XML.
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||