
- •Тема 1 Колекції Структури даних
- •Неузагальнені колекції
- •Деякі інтерфейси неузагальнених колекцій
- •Деякі класи неузагальнених колекцій
- •Узагальнені колекції
- •Тема 2 Файловий ввід-вивід Організація файлового вводу-виводу
- •Байтовий ввід-вивід у файл
- •Двійковий ввід-вивід у файл
- •Символьний ввід-вивід у файл
- •Організація роботи із файлами даних стандарту xml
- •Простір імен System.Xml
- •Класи XmlNode та XmlLinkedNode
- •Клас XmlDeclaration
- •Класи XmlComment та XmlAttribute
- •Клас XmlElement
- •Клас XmlDocument
- •Приклад
- •Тема 3 Делегати та події Клас delegate
- •Делегати в якості параметрів
- •Анонімні методи та узагальнені делегати System.Action, System.Func
- •Комбіновані делегати та шаблон «спостерігач»
- •Події: створення та обробка
Двійковий ввід-вивід у файл
Для вводу-виводу у файл вбудованих у С# типів даних у їх двійковому представленні призначені класи потоків BinaryReader та BinaryWriter. При використанні цих потоків слід пам’ятати, що відповідні двійкові файли будуть містити дані в тому ж вигляді, в якому вони представлені в оперативній пам’яті, тобто у внутрішній двійковій формі представлення.
Класи BinaryReader та BinaryWriter є класами-оболочками (або просто оболочками) для класу FileStream. Клас-оболочка (wrapper class) деякого класу являє собою клас, який інкапсулює в собі екземпляр цього класу. Іншими словами: оболочка − це різновид класу-композита (див. тему «Композиція класів»). Як правило, оболочка класу містить тільки конструктори, в якості параметра яких виступає екземпляр класу.
Клас BinaryWriter є оболочкою деякого базового байтового потоку, який керує виводом двійкових даних. В цьому класі визначені методи, які призначені для запису даних всіх вбудованих у С# типів. Нижче наводяться найбільш важливі елементи класу BinaryWriter.
Елемент класу BinaryWriter |
Призначення |
public BinaryWriter(Stream output); |
Найбільш часто уживаний конструктор класу. Параметр output визначає потік, у який виводяться дані. Для запису у вихідний файл у якості параметра output, як правило, використовують об’єкт класу FileStream. При цьому базовий потік output має бути створений у режимі доступу для запису. Якщо ж параметр output виявляється порожнім, то генерується виняткова ситуація ArgumentNullException. А якщо потік, заданий параметром output, не був відкритий для запису даних, то генерується виняткова ситуація ArgumentException. |
public virtual Stream BaseStream { get; } |
Повертає базовий потік, з яким працює об’єкт класу BinaryWriter. |
public virtual void Close(); |
Закриває потік. При цьому закривається і базовий потік. |
public virtual void Flush(); |
Очищає всі буфери даного потоку та записує дані цих буферів у відповідний файл. |
public virtual long Seek(int offset, SeekOrigin origin); |
Встановлює показчик у потоці на задану позицію. Ця позиція визначається зміщенням на offset байтів відносно значення параметра origin (SeekOrigin.Begin − початок потоку, SeekOrigin.Current − поточна позиція у потоці, SeekOrigin.End − кінець потоку). |
Write |
Ряд методів, які дозволяють записати у двійковий потік значення одного із вбудованих типів даних. |
Клас BinaryReader також є оболочкою деякого базового байтового потоку, який керує вводом двійкових даних. В цьому класі визначені методи, які призначені для зчитування даних всіх вбудованих у С# типів. Нижче наводяться найбільш важливі елементи класу BinaryReader.
Елемент класу BinaryReader |
Призначення |
public BinaryReader(Stream input); |
Найбільш часто уживаний конструктор класу. Параметр input визначає потік, у який вводяться дані із файлу. Як правило, у якості цього параметра використовують об’єкт класу FileStream. При цьому базовий потік input має бути створений у режимі доступу для читання. Якщо потік, заданий параметром input, не був відкритий для зчитування даних або з якихось інших причин, то генерується виняткова ситуація ArgumentException. |
public virtual Stream BaseStream { get; } |
Повертає базовий потік, з яким працює об’єкт класу BinaryReader. |
public virtual void Close(); |
Закриває потік. При цьому закривається і базовий потік. |
public virtual double ReadDouble(); public virtual int ReadInt32(); public virtual char ReadChar(); ... |
Ряд методів, які дозволяють зчитувати у двійковий потік значення одного із вбудованих типів даних. |
Особливості роботи із двійковими потоками розглянемо на прикладі програмної реалізації наступної задачі.
У файлі зберігаються дійсні числа, серед яких немає однакових. Потрібно зчитати дані із файлу у масив та обнулити у файлі найменше значення цього файлу. Значення зміненого файлу вивести на екран. |
class Program { public static void Example(string FileName) { try { // створюємо базовий потік FileStream BaseStream = new FileStream(FileName, FileMode.Open); // визначаємо кількість чисел у файлі через екземпляр базового потоку, оскільки // двійковий потік властивості Length не має long count = BaseStream.Length / 8; // якщо файл не порожній if (count > 0) { // створюємо двійковий потік для зчитування BinaryReader br = new BinaryReader(BaseStream); // змінна, в якій буде збережено номер позиції найменшого значення файлу long pos = -1; // змінна, в якій буде збережено найменше значення файлу double minValue = double.MaxValue; // масив, у який будуть зчитуватися дані із файлу double[] a = new double[count]; // перебір значеньу файлі можна організувати, наприклад, так: for (int i = 0; i < count; i++) { // зчитуємо чергове значення із файлу double value = br.ReadDouble(); // записуємо зчитане значення у масив a[i] = value; // дивимось, чи не було прочитане менше значення, ніж до тепер if (minValue > value) { minValue = value; pos = i; } } // закриваємо двійковий потік зчитування br.Close(); // створюємо двійковий потік для запису BinaryWriter bw = new BinaryWriter(new FileStream(FileName, FileMode.Open)); // встановлюємо показчик у потоці на мінімальне значення bw.Seek((int)pos * 8, SeekOrigin.Begin); // обнуляємо відповідне значення bw.Write((double)0); // закриваємо двійковий потік запису bw.Close(); // відкриваємо новий двійковий потік зчитування br = new BinaryReader(new FileStream(FileName, FileMode.Open)); // виводимо значення зміненого вихідного файлу на консоль for (int i = 0; i < count; i++) { Console.Write(" " + br.ReadDouble()); } // закриваємо двійковий потік зчитування br.Close(); } } catch (Exception e) { Console.WriteLine("Помилка: " + e.Message); } } } |