ЕЛЕМЕНТИ БІБЛІОТЕКИ КЛАСІВ .NET
Бібліотека
класів .NET містить тисячі тисяч класів, інтерфейсів і переліків. Немає
жодної змоги зробити вичерпний опис цих класів навіть у досить об'ємних
публікаціях. Отож в процесі програмування в середовищі .NET необхідно
мати електронний довідник.
У цьому розділі наведемо
короткий огляд деяких методів окремих класів .NET, які здебільшого використовуються
Windows-
програмами.
Класи,
інтерфейси та переліки в бібліотеці .NET згруповані у простори
імен. У кожному з них
зібрані засоби для виконання певних дій: інтерфейс застосувань Windows, робота
з текстом, система безпеки та інших. Простори імен можуть містити інші простори
імен, тобто мають деревовидну структуру.
Наведемо список деяких
найкорисніших просторів імен:
Простір
|
імен
|
Опис
|
Microsoft.CSharp
|
Функції компілювання та генерування коду
|
|
мови C#.
|
||
Microsoft.Win3 2
|
Підтримка подій операційної системи та
|
|
системного реєстра.
|
||
System
|
Кореневий простір імен для більшості класів
|
|
бібліотеки. Містить також типи даних і базові
|
||
класи.
|
||
System.
|
.CodeDom
|
Представляє структуру документа з вихідним
|
кодом.
|
||
System.
|
. Collections
|
Словники, кеш-таблиці, черги, стеки.
|
System.
|
.ComponentModel
|
Реалізує поведінку компонент і керуючих
|
елементів під час виконання та під час
|
||
розробки програми.
|
||
System.
|
. Configuration
|
Програмний доступ до файлів .conf ig.
|
System.
|
Data
|
Класи, які реалізують технологію ADO.NET.
|
System.
|
. Diagnostics
|
Підтримка взаємодії з журналом подій,
|
системними процесами та лічильниками
|
||
продуктивності.
|
||
System.
|
. Directory-
|
Підтримка взаємодії зі службою Active
|
Services
|
Directoryo
|
|
System.
|
. Drawing
|
Класи, які реалізують графічні можливості
|
інтерфейсу GDI+.
|
||
System.
|
, Enterprise-
|
Підтримка взаємодії зі службами COM+.
|
Services
|
||
System.
|
, Globalization
|
Підтримка національних стандартів.
|
System.
|
. IO
|
Ввід та вивід для потоків і файлів.
|
System.
|
.Messaging
|
Підтримка черг подій.
|
System.
|
, Net
|
Підтримка мережевих протоколів.
|
System.
|
, Reflection
|
Доступ до метаданих, розташованих у
|
застосуваннях .NET.
|
||
System.
|
,Resources
|
Утворення та керування ресурсами.
|
System.
|
,Runtime
|
Підтримка різноманітних додаткових
|
можливостей загального оточення мов (CLR).
|
||
System.
|
, Security
|
Система безпеки середовища CLR.
|
System.
|
, ServiceProcess
|
Утворення та управління сервісами Windows.
|
System.
|
. Text
|
Підтримка роботи з текстом і стрічками.
|
System.
|
, Threading
|
Підтримка багатопотоковості.
|
System.
|
,Timers
|
Реалізація таймерів.
|
System.
|
, Web
|
Підтримка роботи через Web-браузер,
|
технології ASP.NET та web-сервісів.
|
||
System.
|
, Windows.Forms
|
Користувацький інтерфейс застосувань
|
Windows.
|
||
System.
|
, Xml
|
Підтримка мови XML та XML-стандартів.
|
Елементи
простору імен можуть бути означені в різних файлах складених модулів.
Просторам
імен можна надавати псевдоніми:
using Forms = System.Windows.Forms;
Глобальний
простір імен має псевдонім global.
Щоб
звернутися до простору імен з використанням його псевдоніма, використовують
синтаксис alias : :.
Наприклад:
Forms::Application.ExitThread()
;
Можлива
ситуація, коли використовують різні складені модулі з однаковими просторами
імен. Наприклад, назву StringLib використовують для позначення простору імен
у складених модулях StringLibrary .dll та Str.
dll:
Складений модуль StringLibrary
. dll
namespace StringLib {
public class StrFunctions {
//функції
роботи зі стрічками
}
}
Складений модуль Str.dll
namespace StringLib {
public class StrFunctions {
//функції
роботи зі стрічками
}
}
При
використанні цих двох складених модулів може виникнути конфлікт імен. Щоб
уникнути такої неоднозначності, необхідно використати зовнішні аліаси:
extern alias StringLibrary; extern alias Str; // деякий код
StringLibrary.StringLib.StrFunctions.Method(); Str.StringLib.StrFunctions.Method() ;
Примітка. Специфікатори до псевдонімів і
зовнішні аліаси доступні у .NET Framework версії 2.
Усі
класи .NET є похідними від System. Object. Цей
клас містить сім методів:
Метод Зміст
ToString Віртуальний метод, який повертає стрічкове представлення об'єкта.Зазвичай, перекривається класами-нащадками.
GetHashCode Віртуальний метод, який повертає кеш (hash) об'єкта для ефективного пошуку екземплярів класів у довідниках або кеш-таблицях (HashTable).
Equals Метод має дві версії: статичну та віртуальну. Перевіряє об'єкти на рівність.
ReferenceEquals Перевіряє на рівність два посилання
GetType Повертає об'єкт класу System.Туре (або нащадка цього класу) з інформацією про тип да них об'єкта.
MemberwiseClone Утворює коротку копію об'єкта: копіює в новий об'єкт дані типів за значенням і повертає посилання на цей об'єкт.
Finalize Метод виконує: роль деструктора. Викликається прибиральником „сміття" і може бути використаний для звільнення ресурсів.
Метод виконує роль деструктора.
Викликається прибиральником „сміття" і може бути використаний для звільнення ресурсів.
Детальніше зупинимося на методах порівняння. Метод ReferenceEquals має сигнатуру public static bool ReferenceEquals(object objA, object objB);
Детальніше зупинимося на методах порівняння. Метод ReferenceEquals має сигнатуру public static bool ReferenceEquals(object objA, object objB);
і перевіряє, чи дві змінні (за посиланням)
посилаються на один і той же екземпляр класу, чи ні. Якщо objA та objB містять
посилання на одну адресу або обидва мають значення null, то
метод повертає результат true. Віртуальну версію
public virtual bool Equals(object obj);
методу Equals використовують
для конкретного екземпляра. Його реалізація в System.Object порівнює
посилання. Проте цей метод призначений для випадку, коли потрібно перекрити
його з метою порівняння даних об'єктів. Ми це вже робили в демонстраційному
класі Point. Статична версія
public static bool Equals(object objA, object objB);
методу Equals працює
аналогічно віртуальній. Метод перевіряє, чи не становить null одне
чи обидва переданих йому посилання. Якщо так, то повертає значення false (одне
посилання null) або true (обидва null). Якщо
ж обидва посилання змістовні, то викликається віртуальна версія Equals.
Операція
порівняння == порівнює посилання. Якщо потрібно
порівнювати дані, то цю операцію необхідно перекрити (як це зроблено в класі Point)
.
Розглянуті
методи порівняння застосовуються до типів за посиланням. Типи за значенням
також є похідними від ob ject. Не
безпосередньо, а через клас System.ValueType. І
у цьому класі вже перекритий метод Equals. Цей
метод перевіряє вже не рівність посилань, а співпадіння даних у всіх полях
структури.
Зазначимо,
що метод ReferenceEquals для типів за
значенням завжди повертає false.
Ключове слово C# string насправді
посилається на базовий клас .NET System. String. Наведемо
деякі методи цього класу:
Метод
|
Зміст
|
Compare
|
Порівнює зміст стрічок з урахуванням регіональних
|
налаштувань
|
|
CompareOrdinal
|
Порівнює зміст стрічок без урахування регіональних
|
налаштувань
|
|
Format
|
Повертає стрічку, відформатовану відповідно до
|
переданого формату
|
|
IndexOf
|
Повертає індекс (починаючи з 0) першого входження
|
підстрічки у стрічці
|
|
IndexOfAny
|
Повертає індекс першого входження у стрічці
|
довільного символу із заданого масиву символів
|
|
LastIndexOf
|
Повертає індекс останнього входження підстрічки у
|
стрічці
|
|
LastIndexOfAny
|
Повертає індекс останнього входження у стрічці
|
довільного символу із заданого масиву символів
|
|
PadLeft
|
Вирівнює стрічку, додаючи декілька заданих символів
|
на початок стрічки
|
|
PadRight
|
Вирівнює стрічку, додаючи декілька заданих символів
|
наприкінці стрічки
|
|
Replace
|
Замінює деякий символ або підстрічку на інший символ
|
або під стрічку
|
|
Split
|
Розбиває стрічку на масив стрічок, використовуючи
|
заданий символ для визначення меж підстрічок
|
|
SubString
|
Повертає підстрічку заданої довжини, починаючи з
|
зазначеної позиції у стрічці
|
|
ToLower
|
Повертає копію стрічки, у якій всі символи переведені у
|
нижній регістр
|
|
ToUpper
|
Повертає копію стрічки, у якій всі символи переведені у
|
верхній регістр
|
|
Trim
|
Вилучає пробіли на початку й наприкінці стрічки
|
TrimEnd
|
Вилучає пробіли наприкінці стрічки
|
TrimStart
|
Вилучає пробіли на початку стрічки
|
Тип string ефективно
зберігає стрічки. Якщо ми одній стрічковій змінній присвоїмо значення іншої, то
насправді обидві змінні будуть посилатися на одну і ту ж ділянку пам'яті. Але
при внесенні змін в одну з них виділиться нова ділянка пам'яті. Якщо ми
спробуємо у циклі замінити кожен символ стрічки на якийсь інший, то таке
копіювання у нові ділянки пам'яті відбудеться певну кількість разів, залежно
від довжини стрічки.
Отож
для маніпуляції зі стрічками доцільно використовувати інший клас представлення
стрічок - System.Text. StringBuilder. Цей
клас має декілька конструкторів:
StringBuilder sb1 = new
StringBuilder("стрічка",
10);
StringBuilder sb1 = new
StringBuilder(10);
StringBuilder sb1 = new
StringBuilder("стрічка");
Перший
конструктор виділяє пам'ять для розташування 10-ти символів та записує текст
"стрічка". Другий - лише виділяє пам'ять. Третій - виділяє пам'ять за
замовчуванням (зазвичай, удвічі більшу за потрібну) та записує текст.
Властивість Length повертає
кількість значущих символів стрічки, а властивість Capacity -
кількість зарезервованих символів.
Перелічимо основні методи
класу StringBuilder:
Метод
|
Зміст
|
Append
|
Додає стрічку до поточної стрічки
|
AppendFormat
|
Додає стрічку, отриману з допомогою специфікатора формату
|
Insert
|
Вставляє підстрічку у поточну стрічку
|
Remove
|
Вилучає символи зі стрічки
|
Replace
|
Замінює деякий символ або підстрічку на інший символ або
|
під стрічку
|
|
ToString
|
Повертає стрічку, приведену до об'єкта String
|
Для
роботи з інформацією про дату та час використовують структури System. DateTime і System.
TimeSpan.
Структура DateTime має
вісім перевантажених конструкторів, які надають зручний синтаксис для утворення
екземплярів структури. Наприклад:
int year = 2005; int month = 5; int day = 8;
DateTime d1 = new
DateTime
(year, month, day) ;
int hour = 21;
int minute = 35;
int second = 20;
int milisecond = 120;
DateTime d2 = new DateTime(year, month,
day, hour, minute, second, milisecond);
Конструктору DateTime можна
передати (останнім параметром) об'єкт класу System.Globalization.Calendar.
Існує декілька нащадків цього класу: GregorianCalendar, JulianCalendar та
інші.
Структура TimeSpan призначена
для представлення часових інтервалів. Ось приклади утворення екземплярів
структури:
int hours = 10; int minutes = 15; int seconds = 30;
TimeSpan ts1 = new
TimeSpan(hours,
minutes,
seconds);
int days = 20;
TimeSpan ts2 = new
TimeSpan(days,10,15,30);
long ticks = 776890;
TimeSpan ts3 = new TimeSpan(ticks);
Останній
конструктор утворює часовий проміжок тривалістю 776890 тікіе (1 тік містить 100 наносекунд).
Структура DateTime має
три статичні властивості, які відображають поточну дату та час, установлені на
комп'ютері:
Властивість
|
Зміст
|
|
Now
|
повертає дату
|
та час
|
Today
|
повертає дату
|
(час - 0:00:00)
|
UtcNow
|
повертає дату
|
та час за Гринвічем
|
Наприклад,
DateTime
today = DateTime.Today;
Решта властивостей
відображає дату та час конкретного екземпляра структури:
Властивість
|
Зміст
|
|
Date
|
повертає дату (час - 0:00:00)
|
|
Day
|
повертає день місяця
|
|
DayOfWeek
|
повертає день тижня
|
|
DayOfYear
|
повертає номер дня в році
|
|
Hour
|
повертає годину
|
|
Minute
|
повертає хвилини
|
|
Second
|
повертає секунди
|
|
TimeOfDay
|
повертає екземпляр типу TimeSpan, який означає час,
|
що минув
|
від півночі
|
||
Year
|
повертає рік
|
|
Структура DateTime містить
низку статичних
|
методів.
|
|
Зокрема:
|
||
Метод
|
Зм ст
|
|
DaysInMonth
|
повертає кількість днів у заданому місяці заданого року
|
|
IsLeapYear
|
повертає true, якщо вказаний рік є високосним
|
|
Parse,
|
перетворюють стрічкове значення дати та часу в
|
екземпляр
|
ParseExact
|
структури DateTime
|
Нестатичні
методи маніпулюють значеннями дати та часу конкретного екземпляра і дозволяють
додавати або віднімати часові інтервали, перетворювати дату та час у стрічкове
представлення та інше.
Структура містить
перевантажений метод ToString(), якому можна передавати
стрічковий параметр з описом формату стрічки, у яку потрібно перетворити
екземпляр структури. Існує значна кількість можливих форматів перетворення.
Наприклад:
DateTime dt = new
DateTime(); dt = DateTime.Now; string s;
s = dt.ToString("dd MMMM yyyy");
//08
травня 2005 s = dt.ToString("dddd,
d-MMM-yy");
//неділя,
8-тра-05
s = dt.ToString("d.MM.yy H:mm:ss");
//8.05.05 9:08:20
Окрім цього, символи
форматування використовують для надання різноманітних вбудованих форматів:
s = dt.ToString("d") ; //08.05.2005
s = dt.ToString("G"); //08.05.2005
1:25:38
Для ознайомлення зі
всіма компонентами форматної стрічки для DateTime і
вбудованих форматів дати та часу потрібно звернутися до довідкової системи.
Структура TimeSpan має
11 загальнодоступних властивостей. Властивості Days, Hours, Minutes,
Seconds, Milliseconds та Ticks повертають
ціле значення відповідно до кількості днів, годин, хвилин, секунд, мілісекунд і
тіків в екземплярі структури. Властивості TotalDays, TotalHours,
TotalMinutes, TotalSeconds, TotalMilliseconds повертають значення
типу double, яке
представляє тривалість екземпляра структури у відповідних одиницях.
Статичні методи FromDays,
FromHours, FromMinutes, FromSeconds, FromMilliseconds, FromTicks дають
змогу утворити новий екземпляр структури. Наприклад, код
TimeSpan tm = TimeSpan.FromDays(2.5);
повертає
інтервал у два з половиною дні.
Метод Parse використовують
для перетворення стрічкового представлення проміжку часу в еквівалентний
екземпляр структури TimeSpan. Методу
передається стрічковий параметр такого формату:
[-][d.]hh:mm:ss[.ff]
де d - кількість днів, hh -
годин, mm - хвилин, ss -
секунд, ff - часток секунди. Знак „мінус"
задає від'ємний інтервал. Елементи в квадратних дужках не є обов' язкові.
Наступний код
утворює екземпляр структури Time Span тривалістю два дні
п'ять годин десять хвилин і 25,8750225 секунд:
TimeSpan tm = TimeSpan.Parse("2.5:10:25.8750225");
Над екземплярами структури TimeSpan можна
виконувати операції додавання та віднімання:
TimeSpan tm1 = TimeSpan.FromDays(2);
TimeSpan tm2 = TimeSpan.FromDays(1);
tm1 += tm2; //tm1 = 3 дні
tm2 -= tm1; //tm2 = -2 дні
Ці ж
дії можна виконати методами Add і Substract.
Операції
множення часових інтервалів і множення часового інтервалу на число не означені.
Над екземплярами
структур DateTime та TimeSpan можна
виконувати операції додавання та віднімання з операндами таких типів:
Операція
|
Операнд 1
|
Операнд 2
|
Тип результату
|
+
|
DateTime
|
TimeSpan
|
DateTime
|
-
|
DateTime
|
TimeSpan
|
DateTime
|
-
|
DateTime
|
DateTime
|
TimeSpan
|
Наприклад:
DateTime dt1 = new DateTime(2005,1,1);
dt1 += TimeSpan.FromHours(45) ;
//
02.01.2005 21:00:00
DateTime dt2 = new DateTime(2006,1,1);
TimeSpan tm1 = dt2 - dt1; //
363.03:00:00
У
просторі імен System.Collections міститься
кілька класів, в екземплярах яких можна зберігати множину елементів, кількість
яких може змінюватися під час виконання програми. Окрім цього, можна
організувати доступ до елементів з використанням індексів, які не є цілими
числами.
Динамічний масие
може змінювати свій розмір у процесі додавання нових елементів. Динамічний
масив реалізований у класі
ArrayList.
Наступний код містить
приклади використання конструкторів класу ArrayList:
ArrayList ar = new ArrayList();
ArrayList ar10 = new
ArrayList(10);
ArrayList
arar = new ArrayList(ar);
Перший
конструктор утворює масив, місткість якого 0. Місткість - це максимальна
кількість елементів, яку може зберігати масив без перебудови.
Другий
конструктор утворює масив, місткість якого 10. Окрім конструктора, задавати (і
отримувати) місткість можна з допомогою властивості Capacity.
Третій
конструктор утворює масив arar, який є
копією масиву ar.
Для
додавання елементів в об'єкт ArrayList використовують
метод Add:
ar.Add("Ue елемент динамічного
масиву");
Нумерація
елементів починається з нуля. Кількість елементів у масиві відображає
властивість Count:
for (int i=0;
i < ar.Count; i++)
Console.WriteLine(ar[i].ToString());
Якщо
місткість масиву дорівнює кількості доданих елементів, то при додаванні нового
елемента масив перебудовується з метою збільшення місткості. Цей процес не
можна назвати ефективним, тому краще зарезервувати достатню місткість масиву.
Загалом, швидкодія роботи динамічних масивів у декілька разів менша порівняно
зі звичайними масивами. Отож при нагоді краще використовувати звичайні масиви.
Елементи
масиву можуть мати довільний тип, оскільки вони зберігаються як об'єкти класу System. Object.
Для
додавання або вставляння елементів використовують методи
int Add(value),
void Insert(index, value) ,
void AddRange(collection),
void
InsertRange(index,
collection),
void SetRange(index, collection).
Наприклад:
ar.Add(new Point(1, 1)); ar.Insert(0,new Point(2, 1)); string[] strs = {"елементи", "для", "Range"};
ar.AddRange(strs) ; ar.SetRange(3,strs) ;
Метод Add додає
елемент наприкінці списку. Метод Insert вставляє елемент у
середину списку, посуваючи всі елементи з індексами, не меншими за index.
Методи AddRange та InsertRange використовують
для додавання або вставляння діапазону елементів. Цей діапазон задається
колекцією (наприклад, масивом).
Метод SetRange не
вставляє діапазон елементів, а замінює ними інші, починаючи із заданого
індексу.
Для вилучення елементів з
динамічного масиву використовують методи
void RemoveAt(index) , void Remove(value) ,
void
RemoveRange(startlndex, collection).
Пошук елементів у
динамічному масиві здійснюють такими методами:
bool Contains(value),
int
IndexOf(value [,startIndex [, count]]),
int
LastIndexOf(value [,startIndex [, count]]),
int
BinarySearch(value [, comparer]), int BinarySearch(index,count,value,comparer) .
Метод Contains повертає true, якщо
динамічний масив містить хоча б один елемент зі значенням value.
Методи IndexOf і LastlndexOf повертають
позицію, відповідно, першого та останнього елемента зі значенням value. Необов'язкові параметри startlndex і count локалізують область пошуку.
Метод BinarySearch застосовують
для пошуку елемента value у
відсортованому масиві. Параметри index та count локалізують область пошуку. Параметр comparer задає правило порівняння об'єктів.
Об'єкт comparer - це
екземпляр деякого класу, який підтримує інтерфейс IComparer і
реалізує метод IComparer.Compare. Об'єкт comparer можна використовувати й у методах
сортування: void
Sort([comparer]), void Sort(index, count, comparer), void
Reverse([index, count]).
Метод Sort впорядковує
елементи динамічного масиву за заданим об'єктом comparer правилом
порівняння. Якщо параметр comparer відсутній
або має значення null, то числа та дати впорядковуються за
зростанням, а символи - за абеткою в порядку зростання. Метод Reverse використовують
для зміни порядку елементів на протилежний.
Як і всі колекції,
клас ArrayList реалізує
інтерфейс IEnumerable, отож
для поелементної ітерації екземпляра цього класу можна використовувати цикл foreach.
Бітоеий масив - це
масив булевих значень. Кожне булеве значення у такому масиві представляється
єдиним бітом (0 або 1). Збереження одного біта вимагає менше пам'яті, ніж
збереження значення типу bool. Як і інші
колекції, бітовий масив є динамічним.
Бітовий
масив реалізований у класі BitArray, який має
декілька конструкторів:
BitArray (length [, defaultValue]) , BitArray (values), BitArray (bits).
Тут length - місткість масиву, а defaultValue - значення, яким потрібно заповнити
елементи масиву при утворенні.
Параметр values може бути масивом елементів типу bool,
byte або int. Відповідний конструктор утворить
бітовий масив з місткістю, яка відповідає довжині масиву-аргумента. Елементи
набудуть значення false, якщо відповідний елемент аргумента
містить значення 0 або false. У
протилежному випадку ці значення будуть true.
Останній
конструктор - це конструктор копій. Тут bits - бітовий
масив.
Як і для звичайного
масиву, доступ до елементів бітового масиву здійснюється з допомогою індексів:
BitArray
bitAr = new BitArray(10);
bitAr[0] = false;
Кількість
елементів у масиві показує властивість Count. Значення
цієї властивості завжди збігається зі значенням властивості Length. Відмінність
між ними в тому, що Count є властивістю лише для читання.
Клас BitArray має декілька
корисних методів.
Методи And,
Or та Xor виконують, відповідно, операції І,
АБО та виключне І між елементами поточного бітового масиву та відповідними
елементами бітового масиву-аргумента.
Метод Not інвертує всі
значення елементів масиву.
Метод CopyTo копіює
елементи з бітового масиву в одномірний масив.
Кеш-таблиця дає змогу зберігати пари ключ
- значення. Ключ у кеш-таблиці можна використовувати для
пошуку відповідного йому значення. Як ключ, так і значення можуть бути
довільного типу.
Кеш-таблиця
реалізована в класі Hashtable. Цей клас
належить до множини словників, тобто класів, які
підтримують інтерфейс IDictionary.
Клас Hashtable містить
одинадцять конструкторів. Найпростіші з них мають сигнатуру
Hashtable ([capacity [,loadFactor]]);
Розглянемо
простий приклад:
Hashtable ht = new Hashtable(7);
ht.Add("Point_1", new
Point());
Point p = (Point)ht["Point_1"];
Конструктор Hashtable( capacity) використовують
найчастіше. Словники найефективніше працюють, коли їх місткість capacity є простим числом. Це спричинено
специфікою алгоритмів, які використовуються у словниках.
Додають об'єкти в Hashtable з
допомогою методу Add:
void Add(£ey, value);
де
обидва параметри мають тип object. Зауважимо,
що словники не мають індексів таких, як масиви. Тому методів типу Insert
також мати не можуть.
Доступ до значення здійснюється з допомогою ключа у
квадратних дужках. Оскільки значення повертається як об' єкт типу object, потрібне явне приведення типу:
(Point)ht["Point_____ 1"
].
Якщо
ключем слугує клас користувача, то в ньому має бути реалізовано алгоритм кеш. Ця реалізація, розташована в перекритому методі GetHashCode, передбачає
виконання таких умов:
•
алгоритм повинен бути швидким;
•
якщо A.Equals(B) дорівнює true, то
методи A.GetHashCode() та B.GetHashCode() повинні
завжди повертати ідентичний кеш;
•
в ідеалі алгоритм повинен видавати значення,
рівномірно розподілені між int. MinValue та int. MaxValue.
Остання
вимога спричинена потребою розташування поруч об'єктів, для яких кеш дає
ідентичний індекс. У цьому випадку бажано, щоб місткість словника була значно
більшою за кількість
розташованих
у ньому елементів. Пропорція між заповненою та незаповненою частинами таблиці
характеризується коефіцієнтом завантаження - loadFactor. За
меншого максимального завантаження ефективніше працюватиме кеш-таблиця, проте
пам'яті вона займатиме більше.
Простий приклад
перекриття методу GetHashCode ми вже
навели, розглядаючи перевантаження операцій на прикладі демонстраційного класу Point, де
неявно використали кеш Microsoft для стрічкового типу:
public
override int GetHashCode()
{
return ToString().GetHashCode();
}
Властивість Count повертає
кількість елементів, які зберігаються в таблиці.
Властивість Keys повертає
колекцію (інтерфейс ICollection), яка
містить ключі таблиці.
Властивість Values повертає
колекцію, яка містить значення таблиці.
Серед методів класу Hashtable зазначимо
такі:
Метод
|
Зміст
|
Add
|
Додає елемент із заданим ключем і значенням
|
Clear
|
Вилучає всі елементи з таблиці
|
Clone
|
Утворює копію таблиці
|
Contains
|
Визначають, чи містить таблиця заданий ключ
|
ContainsKey
|
|
ContainsValue
|
Визначає, чи містить таблиця задане значення
|
Remove
|
Вилучає з таблиці елемент із заданим ключем
|
Відсортований список
- це комбінація динамічного масиву та кеш-таблиці. Його можна розглядати як
кеш-таблицю з функціональністю індексування. Однак це не повнофункціональна
кеш-таблиця, оскільки список не підтримує інтерфейси серіалізації.
Відсортований список
реалізований у класі SortedList. Клас містить шість
конструкторів, з яких найчастіше використовують такий:
SortedList
([capacity]);
Зм ст
|
Властивості і
більшість методів класу SortedList такі ж, як і
в класу Hashtable. Зі
специфічних методів зазначимо такі:
Метод
GetBylndex Повертає
значення на заданій позиції у списку
GetKey Повертає
ключ на заданій позиції у списку
GetKeyList Повертає
інтерфейс IList зі всіма
ключами списку
GetValueList Повертає
інтерфейс IList зі всіма
значеннями списку
IndexOfKey Повертає номер
позиції заданого ключа у списку
IndexOfValue Повертає номер
позиції заданого значення у списку
RemoveAt Вилучає
елемент на заданій позиції у списку
SetByIndex_______ Заміняє значення на заданій позиції у списку____
Доступ до елементів черги здійснюється за принципом „першим увійшов - першим
вийшов" (FIFO - firs in, first out).
Черга реалізована в класі Queue. Клас
містить такі конструктори:
Queue ([capacity [, growFactor]]); Queue (collection);
За
замовчуванням місткість черги capacity дорівнює
32, а фактор збільшення growFactor -
2.0. Фактор збільшення задає множник, на який потрібно помножити місткість,
якщо існуючої недостатньо. Друга версія конструктора використовує для утворення
черги колекцію - екземпляр класу з підтримкою інтерфейсу ICollection.
Елементи черги можуть мати
довільний тип.
Властивість Count повертає
кількість елементів у черзі.
Із методів класу Queue зазначимо
такі:
Метод
|
Зміст
|
Clear
|
Вилучає всі елементи з черги
|
Contains
|
Визначає, чи містить черга заданий елемент
|
CopyTo
|
Копіює елементи черги в одновимірний масив
|
Dequeue
|
Повертає значення першого елемента черги та вилучає його з
|
черги
|
|
Enqueue
|
Додає елемент наприкінці черги
|
Peek
|
Повертає значення першого елемента черги, однак не вилучає
|
його з черги
|
|
ToArray
|
Копіює елементи черги в масив
|
Доступ
до елементів стека здійснюється за принципом „останнім
увійшов - першим вийшов" (LIFO - last in, first out).
Стек реалізований
у класі Stack. Клас налічує такі конструктори:
Stack
([capacity]);
Stack
(collection);
За
замовчуванням місткість стеку capacity дорівнює
10. Друга версія конструктора для утворення стека використовує колекцію.
Елементи
стека можуть мати довільний тип.
Властивість Count повертає
кількість елементів у стеку.
Із методів класу Stack зазначимо
такі:
Метод
|
Зміст
|
Clear
|
Вилучає всі елементи зі стека
|
Contains
|
Визначає, чи містить стек заданий елемент
|
CopyTo
|
Копіює елементи стека в одновимірний масив
|
Peek
|
Повертає елемент на вершині стека, проте не вилучає його зі стека
|
Pop
|
Повертає елемент на вершині стека та вилучає його зі стека
|
Push
|
Додає елемент на вершину стека
|
ToArray
|
Копіює елементи стека в масив
|
Простір
імен System.IO містить
понад 50 класів, інтерфейсів і переліків, які дають змогу працювати з файлами
та каталогами (папками). Додатково простір імен System.Windows.Forms містить
декілька діалогових форм вибору файлів.
При
роботі з файлами доцільно детально ознайомитися з функціональними можливостями
елементів System.IO, оскільки Microsoft
передбачив дуже широкий набір інструментів маніпулювання файловою
системою. Ми ж розглянемо лише декілька з них.
Для
поодиноких операцій над файлами використовують клас File. Він містить
лише статичні методи, отож утворювати екземпляр класу нема необхідності.
Серед загальнодоступних
методів класу File зазначимо
такі:
|
|
Метод
|
Зміст
|
AppendText
|
Додає текст в існуючий файл
|
Copy
|
Копіює файл
|
Create
|
Утворює файл
|
CreateText
|
Утворює файл і відкриває його для запису тексту
|
Delete
|
Вилучає файл
|
Exists
|
Перевіряє, чи існує файл
|
GetAttributes
|
Повертає атрибути файла
|
Move
|
Переміщає файл
|
Open
|
Відкриває файл
|
OpenRead
|
Відкриває файл для читання
|
OpenText
|
Відкриває файл для читання тексту
|
OpenWrite
|
Відкриває файл для запису
|
SetAttributes
|
Встановлює атрибути файла
|
Клас File містить
також кілька методів для повернення або встановлення дати утворення файла,
останнього доступу, останнього запису.
Наведемо
простий приклад використання класу File:
if (openDlg.ShowDialog()==DialogResult.OK){ string s = openDlg.FileName;
FileAttributes fa = File.GetAttributes(s); if
((fa & FileAttributes.Readonly) == FileAttributes.Readonly) MessageBox.Show("+a^ " + s + " є лише для читання";
}
Цей
код активізує діалогову форму вибору файла та записує у змінну fa атрибути
файла, які є набором бітових прапорців.
Якщо
цей набір у позиції ознаки ReadOnly містить
ненульовий біт, то виводиться повідомлення.
Якщо потрібно
виконати декілька операцій над файлом, то значно ефективнішим буде використання
класу FileInfo. Для роботи з
файлом з допомогою цього класу потрібно утворити об'єкт. Єдиний конструктор
класу має просту сигнатуру: public FileInfo(string fileName) ;
Клас FileInfo має
такі загальнодоступні властивості:
Властивість
|
Зміст
|
Attributes
|
Атрибути файла
|
CreationTime
|
Час утворення файла
|
Directory
|
Каталог (тип DirectoryInfo), у якому розташований
|
файл
|
|
DirectoryName
|
Назва каталогу, у якому розташований файл
|
Exists
|
Повертає true, якщо файл існує
|
Extension
|
Розширення файла
|
FullName
|
Повний шлях до файла та назва файла
|
LastAccessTime
|
Час останнього доступу до файла
|
LastWriteTime
|
Час останньої модифікації файла
|
Length
|
Розмір файла
|
Name
|
Назва файла
|
Серед
загальнодоступних методів класу FileInfo
|
|
зазначимо
такі:
|
|
Метод
|
Зміст
|
AppendText
|
Додає текст у файл
|
CopyTo
|
Копіює файл
|
Create
|
Утворює файл
|
CreateText
|
Утворює текстовий файл
|
Delete
|
Вилучає файл
|
MoveTo
|
Переміщує файл
|
Open
|
Відкриває файл
|
OpenText
|
Відкриває файл для читання тексту
|
OpenWrite
|
Відкриває файл для запису
|
Аналогічно
до файлів, для роботи з каталогами бібліотека .NET містить
клас Directory зі
статичними методами та клас
DirectoryInfo, екземпляр
якого використовують за необхідності здійснення декількох операцій з каталогом.
Серед методів класу Directory зазначимо
такі:
Метод
|
Зміст
|
CreateDirectory
|
Утворює новий каталог
|
Delete
|
Знищує каталог
|
Exists
|
Визначає, чи існує каталог
|
GetCurrentDirectory
|
Повертає поточний каталог
|
GetDirectories
|
Повертає імена всіх підкаталогів у каталозі
|
GetFiles
|
Повертає імена всіх файлів у каталозі
|
GetFileSystemEntries
|
Повертає імена всіх файлів і підкаталогів
|
GetLogicalDrivers
|
Повертає список логічних дисків
|
GetParent
|
Повертає назву батьківського каталогу
|
Move
|
Переміщує каталог
|
SetCurrentDirectory
|
Встановлює поточний каталог
|
Клас Directory містить
також декілька методів для повернення або встановлення дати утворення файла,
останнього доступу, останнього запису.
Властивості
класу DirectoryInfo подібні до
властивостей класу FileInfo. З додаткових
властивостей Зазначимо Root (повертає
кореневу частину шляху) та Parent (повертає об'єкт, який
є батьківським каталогом).
Методи класу DirectoryInfo подібні
до методів класу Directory.
Бібліотека
.NET
дає змогу програмі вести моніторинг змін у файловій системі. Ця
можливість реалізована в класі
FileSystemWatcher, який відстежує такі події:
Подія
|
Зміст
|
Changed
|
Модифікація файла або каталогу
|
Created
|
Утворення файла або каталогу
|
Deleted
|
Вилучення файла або каталогу
|
Error
|
Переповнення внутрішнього буфера
|
Renamed
|
Перейменування файла або каталогу
|
Щоб
опрацювати одну із цих подій, необхідно утворити відповідну функцію та долучити
її до списку обробників події.
Наприклад, для опрацювання події внесення змін у файли можна
написати:
public static void OnChanged(
object sender, FileSystemEventArgs e){ MessageBox.Show(e.FullPath+": " +
e.ChangeType) ;
}
Сигнатура
методу повинна відповідати сигнатурі делегата FileSystemEventHandler. Клас FileSystemEventArgs
має три властивості, які характеризують подію: Name або
FullPath містять
назву чи повний шлях зміненого файла (каталогу), а ChangeType -
ознаку змін.
Наведемо тепер фрагмент коду, який демонструє використання класу FileSyst emWa tcher:
FileSystemWatcher fsw = new
FileSystemWatcher("C:\\"); fsw.Filter = "*.txt";
fsw.Changed += new
FileSystemEventHandler(OnChanged) ; fsw.NotifyFilter =
NotifyFilters.LastAccess|NotifyFilters.LastWrite; fsw.EnableRaisingEvents = true;
Код
утворює об'єкт класу FileSystemWatcher і дає
вказівку цьому об'єкту відстежувати зміни на диску C: у файлах
із розширенням .txt. Потім додає обробник подій, який клас FileSystemWatcher активізує
при отриманні повідомлення від операційної системи про внесення змін у txt-файли,
зазначає, які події відстежувати, та вмикає моніторинг.
Перелічимо властивості
класу FileSyst emWa tcher:
Властивість
|
Зміст
|
EnableRaisingEvents
|
Увімкнення/вимкнення моніторингу
|
Filter
|
Фільтр файлів для відстеження
|
IncludeSubdirectories
|
Ознака моніторингу дочірніх підкаталогів
|
InternalBufferSize
|
Розмір внутрішнього системного буфера
|
NotifyFilter
|
Список подій для моніторингу
|
Path
|
Шлях, по якому відстежують зміни
|
SynchronizingObject
|
Керування потоком виконання, який відстежує
|
зміни
|
Властивість NotifyFilter -
це набір прапорців з перерахунку NotifyFilters:
Ознака
|
Значення
|
Моніторинг змін
|
Attributes
|
4
|
Атрибутів файлів
|
CreationTime
|
64
|
Часу створення файлів і каталогів
|
DirectoryName
|
2
|
Імен каталогів
|
FileName
|
1
|
Імен файлів
|
LastAccess
|
32
|
Часу останнього доступу
|
LastWrite
|
16
|
Часу останнього запису
|
Security
|
256
|
Атрибутів безпеки
|
Size
|
8
|
Розміру
|
Обмін
інформацією передбачає наявність двох суб'єктів, які є джерелом та адресатом
цієї інформації. Одним із суб' єктів обміну інформацією є програма. Якщо
інформація передається від програми, то кажуть, що інформація виводиться. І навпаки, якщо
програма отримує інформацію, то маємо справу з введенням інформації.
Суб'єкт
обміну інформацією, який може її зберігати, називають сховищем
даних. Це може бути файл, оперативна пам'ять, мережеве з'єднання, URL та
інше.
Механізм,
який реалізує процес обміну інформацією, називають потоком
введення/виведення. При утворенні потоку йому вказують сховище даних, з
яким він працюватиме.
Бібліотека .NET чітко
розділяє сховища даних і потоки. Власне тому розглянуті у попередньому розділі
класи роботи з файлами дають змогу широко маніпулювати файлами загалом, однак
майже зовсім не містять функцій зчитування та запису даних.
Усі
потоки .NET є екземплярами класів, похідних від базового абстрактного
класу Stream. Цей клас має
п'ять загальнодоступних властивостей:
Властивість
|
Зміст
|
CanRead
|
Повертає ознаку доступу до читання даних
|
CanSeek
|
Повертає ознаку коректності переходу на задану позицію в потоці
|
CanWrite
|
Повертає ознаку доступу для запису даних
|
Length
|
Повертає довжину потоку в байтах
|
Position
|
Повертає поточну позицію у потоці
|
Властивості CanRead,
CanSeek і CanWrite повертають
значення true або false. Доступ
до читання або запису визначається при утворенні потоку. Всі властивості (окрім
Posit ion) мають
доступ лише для читання.
Клас Stream містить
одне статичне поле: Null. Це поле повертає потік, з яким не
пов' язане сховище даних. При читанні з потоку Stream.Null ніякі
дані не повертаються, а при записі в потік - не зберігаються.
Перелічимо
загальнодоступні методи класу Stream:
Метод
|
Зміст
|
BeginRead
|
Починає асинхронну операцію зчитування
|
BeginWrite
|
Починає асинхронну операцію записування
|
Close
|
Закриває потік і звільняє зайняті ним ресурси
|
EndRead
|
Очікує завершення асинхронної операції зчитування
|
EndWrite
|
Очікує завершення асинхронної операції записування
|
Flush
|
Записує всі дані з внутрішнього буфера у сховище даних
|
Read
|
Зчитує послідовність даних
|
ReadByte
|
Зчитує один байт
|
Seek
|
Установлює позицію в потоці
|
SetLength
|
Установлює довжину потоку
|
Write
|
Записує послідовність байт
|
WriteByte
|
Записує один байт
|
Потоковий
клас FileStream призначений
для читання та запису як текстових, так і двійкових даних у довільний файл.
Зазначимо, що існують спеціалізовані класи для деяких типів файлів, які є дещо
ефективнішими порівняно з FileStream. Зокрема, нижче ми
розглянемо класи роботи з текстовими файлами.
Клас FileStream має
дев'ять конструкторів. Чотири з них використовують дескриптор файла Windows у
стилі старого API.
Ми
їх не розглядатимемо. Решта конструкторів опишемо наступною схемою:
public FileStream( string path, FileMode mode [,FileAccess access [,FileShare share [,int bufferSize [,bool useAsync ]]]]);
Параметр path задає
повне ім'я файла.
Параметр mode визначає режим файла і може набувати одне
із значень переліку FileMode: Append (додати), Create
(утворити), CreateNew (утворити
новий), Open (відкрити), OpenOrCreate (відкрити
або утворити), Truncate (обрізати).
Зауважимо, що некоректне значення mode може
породжувати виняток (наприклад, Open для
неіснуючого файла).
Параметр access доступу до файла може набувати одне зі
значень переліку FileAccess: Read (читання), ReadWrite
(читання та запис), Write (запис).
Очевидно, що при утворенні потоку з атрибутом FileAccess.Read запис
у файл буде недоступним.
Параметр share визначає доступ до файла з інших потоків.
Він може набувати одне зі значень переліку FileShare: None (нема), Read (читання), ReadWrite (читання
та запис), Write (запис). Якщо потік успішно
утворений, то інші потоки можуть працювати з цим файлом відповідно до значення
параметра share зазначеного потоку.
Параметр bufferSize задає бажаний розмір у байтах
внутрішнього буфера читання. Параметр useAsync визначає,
чи буде файл відкрито асинхронно.
Наведемо приклади утворення файлових потоків:
FileStream fs1 = new
FileStream(
@"C:\Temp\File1.cs", FileMode.Create);
FileStream fs2 = new
FileStream(@"C:\Temp\File2 .cs",
FileMode.Create, FileAccess.Write);
FileStream
fs3 = new
FileStream(@"C:\Temp\File3.cs
FileMode.Create, FileAccess.Read, FileShare.None, 2048, true);
Перший
конструктор утворює потік і файл File1.cs з доступом
„читання-запис" та надає іншим потокам доступ на читання. Другий конструктор
утворює файл File2.cs з доступом
лише для запису та надає іншим потокам доступ на читання. Третій конструктор
утворює файл File3.cs для
асинхронного доступу лише для читання, без права доступу іншим потокам, а також
установлює розмір буфера.
Клас FileStream, окрім
успадкованих від Stream, має такі
властивості:
Властивість
|
Зміст
|
Handle
|
Дескриптор операційної системи для відкритого файла
|
IsAsync
|
Повертає ознаку асинхронності доступу
|
Name
|
Повертає ім'я об'єкта FileStream
|
Клас FileStream має
два додаткових методи: Lock та Unlock. Метод Lock забороняє
доступ до файла іншим потокам, а Unlock скасовує цю заборону.
За
синхронних операцій введення-виведення робота програми зупиняється до
завершення цих операцій. Якщо програма працює з великими файлами або з
мережевими потоками, то складається враження, що вона „зависла".
За
асинхронного введення-виведення виділяється окремий потік виконання. Це дає
змогу програмі працювати, не очікуючи завершення операції введення-виведення.
Зазначимо, що асинхронні методи не можна активізувати у випадку, якщо код,
наступний за операцією введення-виведення, використовує результат цієї
операції.
Щоб
надати можливість повідомити програму про завершення асинхронної операції,
список параметрів асинхронних методів містить параметр типу AsyncCallback. Цей
параметр дає змогу означити функцію зворотного виклику, що передається як
делегат. Коли асинхронна операція завершилася, то викликається функція
зворотного виклику, в якій можна працювати з результатами операції.
Делегат AsyncCallback означений
так:
public delegate void
AsyncCallback(IAsyncResult ar);
Оголосимо
потокову змінну та функцію зворотного виклику:
public FileStream fs;
public void OnReadFinished(IAsyncResult asyncResult) {
int ReadCount = fs.EndRead(asyncResult);
MessageBox.Show("Прочитано "+ReadCount+" байт.");
}
Наведемо тепер приклад
використання асинхронних методів:
//пам'ять для читання
byte[] buffer = new byte[100 00 0];
//відкриття файла
fs = new
FileStream(@"c:\temp\file1.cs",
FileMode.Open, FileAccess.Read, FileShare.None, 2048, true); //присвоєння делегату функції зворотного виклику AsyncCallback acb = new
AsyncCallback(OnReadFinished);
//асинхронне читання
fs.BeginRead(buffer, 0, 100000, acb, null); // наступний код, який виконуватиметься без //
очікування на завершення операції читання
Як
тільки операцію асинхронного введення буде завершено, активізується метод OnReadFinished.
Зауважимо:
якщо файл відкритий для синхронного доступу, то асинхронні методи працюватимуть
також синхронно.
Клас MemoryStream призначений
для обміну даними між програмою та областю пам'яті, яка є в цьому випадку
сховищем даних.
Клас має декілька
конструкторів. Найінформативніший з них такий:
public MemoryStream(
[byte[] buffer [, int index[, int
count [, bool writable[, bool publiclyVisible]]]]]);
З цього
синтаксису бачимо, що конструктор може не мати аргументів або мати лише
декілька з них.
Параметр buffer задає масив байтів, який слугуватиме
сховищем даних. Якщо аргумент відсутній, то утворюється динамічний буфер з
нульовим розміром.
Параметр index зазначає індекс у масиві buffer, з якого починається сховище даних. За
замовчуванням параметр дорівнює нулю.
Параметр count зазначає кількість байт в масиві buffer, виділених для сховища даних.
Параметр writable задає
значення властивості CanWrite.
Параметр publiclyVisible визначає, чи можна отримати масив
(тобто сховище даних) з допомогою методу GetBuffer.
Наступний код демонструє
використання класу MemoryStream для
копіювання файла в пам'ять:
FileStream fs =
File.OpenRead(@"c:\temp\file .cs") ;
MemoryStream ms = new
MemoryStream();
ms .SetLength(fs.Length);
fs.Read(ms.GetBuffer(), 0, (int)fs.Length);
ms.Flush();
fs.Close();
Клас MemoryStream, окрім
успадкованих від Stream, має
додаткову властивість Capacity. Ця
властивість повертає або встановлює кількість байт, виділених для потоку.
Клас MemoryStream має
також два додаткових методи: GetBuffer повертає
(якщо дозволено) внутрішній буфер, а WriteTo записує дані
потоку в інший потік.
Клас NetworkStream отримує
та відсилає через мережу байти процесу, який працює на другому кінці мережевого
з'єднання. Цей клас розташований у просторі імен System.Net.Sockets.
Для
утворення потоку необхідно задати мережеве з' єднання на основі сокета. Сокет -
це об'єкт класу Socket або успадкованих від Socket класів: TcpListener,
TcpClient та інших.
Для
означення сокета потрібно задати адресу хоста (host). Ця
адреса може бути числовою адресою TCP/IP або іменем хоста, яке операційна
система може перетворити в числову адресу. Список таких імен хостів можна
отримати з допомогою статичних методів класу Dns, розташованого
у просторі імен System.Net. Ім'я хоста localhost представляє комп'ютер, на якому
запущено програму.
Другим
елементом, який означує сокет, є номер порту (port). Порти з номерами від 0 до 49151 вже призначені
конкретним службам. Отож у власних програмах доцільно використовувати порти з
номерами від 49152 до 65536.
Узагальнений конструктор
класу NetworkStream має вигляд:
public NetworkStream( Socket socket,
[, FileAccess access[, bool ownsSocket]]);
Параметр socket задає
сокет і є обов'язковим.
Параметр access визначає доступ до сокета і може набувати
одне зі значень переліку FileAccess.
Параметр ownsSocket визначає, чи потік буде власником
сокета. Якщо так, то сокет буде знищуватися при завершенні роботи потоку.
Деякі
класи сокетів (наприклад, TcpClient) містять
вбудовані мережеві потоки, які можна отримати методом
GetStream.
Клас NetworkStream, окрім
успадкованих від Stream, має
додаткову властивість Capacity, яка повертає
або встановлює кількість байт, виділених для потоку.
Клас NetworkStream має
також два додаткових методи: GetBuffer повертає
внутрішній буфер, а WriteTo записує дані
потоку в інший потік.
Наступний код демонструє
процес введення даних з деякого мережевого сервера, тобто програма діє як
клієнт:
byte[] buffer = new byte[2048];
TcpClient socket = new
TcpClient("localhost", 65535);
NetworkStream ns = socket.GetStream();
int count = ns.Read(buffer, 0, 2048);
ns.Close();
socket.Close ();
У
цьому прикладі ми не утворювали екземпляр потоку, а використали для читання
даних уже існуючий потік сокета. Метод Read робить спробу прочитати й розмістити
в buffer перших 2048 байт,
викладених в порті з номером 65535 комп'ютера, заданого хостом. Якщо на
цьому комп'ютері відсутня програма (сервер), яка викладає дані на порт 65535,
то виконання наведеного коду завершиться винятком SocketException.
Наступний код демонструє
процес викладання даних на деякий порт, тобто програма діє як сервер:
string msg="3B'fl30K із сервером
встановлений";
TcpListener tcpl = new
TcpListener(65535);
tcpl.Start() ;
Socket sckt = tcpl.AcceptSocket();
if (sckt.Connected) { NetworkStream
ns= new NetworkStream(sckt); byte[] bytes= Encoding.ASCII.GetBytes(msg);
ns.Write(bytes, 0, bytes.Length); ns.Flush(); ns.Close(); sckt.Close();
}
Метод tcpl. Start дає
команду почати прослуховування порту в очікуванні нового з' єднання по мережі.
Метод AcceptSocket очікує
реального підключення клієнта. Коли підключення відбулося, метод повертає
об'єкт sckt класу Socket, який
використовують для пересилання даних.
З
метою підвищення ефективності коду в .NET реалізовано успадкований від Stream клас BufferedStream, який
додає рівень буферизації до іншого потоку для операцій читання та запису. Цей
клас не може бути успадкованим. При використанні класу BufferedStream операційна
система надає дані блоками, які забезпечують найкращу продуктивність. Окрім
того, клас може зберігати в пам'яті результати декількох операцій запису, і
записати їх у сховище даних лише тоді, коли цей запис буде найефективнішим.
Простір імен System.Security.Cryptography має
ще один успадкований від Stream клас - CryptoStream. Цей
клас є потоковою реалізацією криптографії. Його можна додати до існуючого
потоку з метою шифрування інформації.
Розглянуті
вище потокові класи є зручними для переміщення даних як послідовності байтів.
Однак вони недостатньо ефективні для операцій над даними. Наприклад, щоб
отримати з файла ціле число типу int, необхідно
прочитати 4 байти в масив байтів, який після цього потрібно інтерпретувати як
ціле.
Щоб
забезпечити більш структурований доступ до даних із потоків, у просторі System.IO розташовано
кілька класів для зчитування та запису даних.
Клас BinaryWriter призначений
для запису значення типізованої змінної в потік. Конструктор класу має такий
синтаксис:
BinaryWriter([Streamoutput,[Encoding
encoding]]);
Параметр output зазначає потік, з яким працюватиме клас.
Параметр encoding дає змогу
під час виводу символьних даних в потік конвертувати їх в інші кодові формати.
Наступний
код демонструє використання класу
BinaryWriter:
FileStream fs=File.Create (@"c: \temp\file.dat") ;
BinaryWriter bw = new
BinaryWriter(fs);
bw.Write((float) 3.14);
int i = 10;
bw.Write (i);
string s = "стрічка";
bw.Write (s);
bw.Flush();
bw.Close();
Клас BinaryWriter має
єдину властивість BaseStream, яка повертає потік, в який
пише об' єкт класу.
Перелічимо
загальнодоступні методи класу BinaryWriter:
Метод
|
Зміст
|
Close
|
Закриває об'єкт класу та відповідний йому потік
|
Flush
|
Записує всі дані з буфера у сховище даних потоку
|
Seek
|
Установлює позицію в потоці
|
Write
|
Записує типізоване значення в потік
|
Зазначимо,
що метод Write сильно перевантажений, оскільки
підтримує запис більшості основних типів даних.
Клас BinaryReader призначений
для читання даних з потоку в типізовані змінні. Конструктор класу має такий
синтаксис:
BinaryReader(Stream input, [Encoding encoding]);
Параметр input визначає потік, з яким працюватиме клас.
Необов'язковий параметр encoding дає
змогу у процесі читання символьних даних з потоку конвертувати їх в інші кодові
формати.
Наступний код демонструє
використання класу BinaryReader:
FileStream fs =
File.OpenRead(@"c:\temp\file.dat");
BinaryReader br = new
BinaryReader(fs);
float f = br.ReadSingle();
int i = br.ReadInt32();
string s = br.ReadString();
br.Close();
Клас BinaryReader має
єдину властивість BaseStream, яка повертає потік, з якого
читає об' єкт класу.
Призначення
наступних методів класу очевидне з назви: Close, ReadBoolean, ReadByte, ReadBytes, ReadChar, ReadChars,
ReadDecimal, ReadDouble, ReadInt16, ReadInt32, ReadInt64, ReadSByte,
ReadSingle, ReadString, ReadUInt16, ReadUInt32, ReadUInt64. Окрім перелічених клас має ще два методи: PeekChar повертає наступний символ, не
змінюючи позиції в потоці, а Read повертає символі змінює позицію.
Класи FileStream,
BinaryReader та BinaryWriter використовують
для читання та запису текстових файлів. Однак, з метою підвищення ефективності
та зручності програмування, доцільно використовувати для роботи з текстом
спеціальні класи, які є нащадками абстрактних класів TextReader та
TextWriter. Методи
цих класів вміють читати та записувати стрічку, тобто набір символів, який завершується
комбінацією „повернення каретки - переведення стрічки" ((char) 13 (char)
10). Окрім цього, класи автоматично
розпізнають і підтримують задане у файлі кодування символів (ASCII, Unicode,
UTF7, UTF8).
Наведемо
деякі загальнодоступні методи класу TextReader:
Метод
|
Зміст
|
Close
|
Закриває об' єкт і звільняє зайняті ним ресурси
|
Peek
|
Повертає наступний символ без зміни позиції
|
Read
|
Читає символи з відповідного об' єктові потоку
|
ReadBlock
|
Читає буфер з відповідного об' єктові потоку
|
ReadLine
|
Читає стрічку символів з відповідного об' єктові потоку
|
ReadToEnd
|
Читає символи від поточної позиції до кінця потоку
|
Клас TextWriter має
такі методи:
|
|
Метод
|
Зміст
|
Close
|
Закриває об' єкт і звільняє зайняті ним ресурси
|
Flush
|
Записує всі дані з буфера у сховище даних
|
Write
|
Записує символи у відповідний об' єктові потік
|
WriteLine
|
Записує стрічку у відповідний об' єктові потік
|
Клас TextWriter має
також властивості:
|
|
Властивість
|
Зміст
|
Encoding
|
Повертає поточне кодування тексту
|
FormatProvider Повертає об'єкт із урахуванням культурозалежних
|
|
аспектів форматування
|
|
NewLine
|
Повертає або встановлює послідовність символів, які
|
означають кінець стрічки тексту
|
Реалізацією
класів TextReader та TextWriter для
роботи з потоками є класи StreamReader та StreamWriter.
Узагальнена схема
конструктора класу StreamReader має такий
вигляд:
public StreamReader(
Stream stream | string path [,
Encoding encoding
[, bool detectEncodingFromByteOrderMarks [, int bufferSize]] ]);
Зазначимо,
що схема не охоплює синтаксис усіх конструкторів класу. Режим і тип доступу не
використовують, оскільки клас призначений лише для читання.
Клас StreamReader може
читати дані з файла (параметр path) або
з іншого потоку (параметр stream).
Параметр encoding задає метод кодування.
Параметр detectEncodingFromByteOrderMarks
зазначає, чи шукати ознаку
кодування символів у файлі (потоці).
Параметр bufferSize задає мінімальний розмір буфера для
читання.
Екземпляр
класу StreamReader можна також
отримати з інших класів. Наприклад, екземпляр цього класу повертають методи OpenText і CreateText класу FileInfo.
Клас StreamWriter працює
практично так само, як і StreamReader, тільки використовується для запису у
файл або інший потік. Конструктори класу StreamWriter використовують
ті ж параметри, що й конструктори класу StreamReader.
Наступний код
демонструє використання класів StreamReader і StreamWriter:
FileStream fs = File.Create(@"e:\File.txt");
//Запис у файл
StreamWriter sw = new
StreamWriter(fs);
sw . WriteLine ( "Записано класом StreamWriter.");
sw.Flush();
sw.Close();
//Читання з файла
StreamReader sr = new
StreamReader(@"e:\File.txt") ;
MessageBox.Show(sr.ReadLine());
sr.Close();
Класи StringReader і StringWriter також
є дочірніми для класів TextReader і TextWriter. Сховищем
даних для цих класів є стрічка. Класи StringReader і StringWriter мають
такі ж методи та властивості, як і класи StreamReader - StreamWriter. Додатково
клас StreamWriter має метод GetStringBuilder, який
повертає об'єкт класу StringBuilder.
Модифікуємо
попередній код під використання класів StringReader і StringWriter:
StringBuilder
sb = new StringBuilder();
//Запис у стрічку
StreamWriter sw = new
StreamWriter(sb); sw.WriteLine ("Записано класом StreamWriter.");
sw.Close (); //Читання зі стрічки StreamReader
sr = new
StreamReader(sb.ToString()); MessageBox.Show(sr.ReadToEnd()); sr.Close();
Серіалізація - це
процес перетворення даних об'єкта у формат, який можна зберігати або
транспортувати. Серіалізація дає змогу записати об'єкт у сховище даних з
допомогою потоку. Зворотний процес - відновлення об'єкта з допомогою потоку зі
сховища даних - називають десеріалізацією.
Серіалізувати можна
лише об'єкти класів, які перед своїм оголошенням містять атрибут [Serializable].
.NET
надає дві технології серіалізації.
Бінарна (двійкова) серіалізація передбачає
збереження точної копії об'єкта. Це може бути корисним для відтворення об'єкта
в різних сеансах роботи програми, для передавання між різними програмами та
мережею. З метою відтворення бінарно серіалізованого об'єкта програма повинна
знати його тип. У випадку бінарної серіалізації об'єкт-десеріалізатор залежний
від версії модуля, у якому серіалізовано стан відповідного об'єкта.
Наступна схема демонструє
процес бінарної серіалізації- десеріалізації.
//клас Sample будемо
серіалізувати [Serializable] public class Sample { public string Title;
}
//фрагмент
коду серіалізації Sample obj = new Sample(); obj.Title = "Об'єкт класу Sample";
FileStream writer = new FileStream ("c:\\Sample.dat", FileMode.Create);
BinaryFormatter bf = new
BinaryFormatter(); //бінарна серіалізація bf.Serialize(writer,
obj); writer.Close();
//фрагмент
коду десеріалізації FileStream reader = new
FileStream("c:\\Sample.dat", FileMode.Open); Sample newobj =
(Sample)bf.Deserialize(reader);
Клас BinaryFormatter оголошений у просторі імен System.Runtime.Serialization.Formatters.Binary.
XML-серіалізація
дає змогу зберегти лише загальнодоступні властивості та поля. Здебільшого цього
достатньо для смислового відтворення об'єкта. Оскільки XML -
відкритий стандарт, XML- серіалізація є хорошим засобом спільного використання даних
у мережі. У випадку XML-серіалізації проблема версійності складеного модуля, яким
виконано серіалізацію стану об' єкта, не виникає. Проте необхідно зважати на
суттєве зростання пакетів серіалізованої інформації (до об'єму даних додається
суттєвий об'єм XML-розмітки).
XML-серіалізація
може бути виконана, наприклад, наступним кодом:
XmlSerializer ser = new
XmlSerializer(typeof(Sample)); TextWriter writer = new
StreamWriter("c:\\Sample.xml"); ser.Serialize(writer,
obj); writer.Close();
Клас XmlSerializer оголошений у просторі імен System. Xml.Serialization.
Різновидом-XML серіалізації є SOAP серіалізація,
яка використовує відкритий стандарт SOAP. Для її реалізації можна
використати спеціалізований клас SoapFormatter, оголошений
у просторі імен System.Runtime.Serialization.
Formatters.Soap.
Немає коментарів:
Дописати коментар