Файл - іменована інформація на зовнішньому носієві, наприклад на жорсткому або гнучкому магнітному диску. Логічно файл можна представити як кінцева кількість послідовних байтів, тому такі пристрої, як дисплей, клавіатура і принтер, також можна розглядати як файли. Передача даних із зовнішнього пристрою в оперативну пам'ять називається читанням, або введенням, зворотний процес - записом, або виведенням.
Введення-виведення в С# виконується за допомогою підсистеми введення-виведення і класів бібліотеки .NET. У цьому розділі розглядається обмін даними з файлами і консоллю. Обмін даними реалізується за допомогою потоків.
Потік (stream) - це абстрактне поняття, що відноситься до будь-якого перенесення даних від джерела до приймача. Потоки забезпечують надійну роботу як із стандартними, так і з визначеними користувачем типами даних. Потік визначається як послідовність байтів і не залежить від конкретного пристрою, з яким проводиться обмін (оперативна пам'ять, файл на диску, клавіатура або принтер).
Обмін з потоком для підвищення швидкості передачі даних проводиться, як правило, через спеціальну область оперативної пам'яті - буфер. Буфер виділяється для кожного відкритого файлу. При записі у файл вся інформація спочатку прямує в буфер і там накопичується до тих пір, поки весь буфер не заповниться. Тільки після цього або після спеціальної команди скидання відбувається передача даних на зовнішній пристрій. При читанні з файлу дані спочатку прочитуються в буфер, причому не стільки, скільки запрошується, а скільки поміщається в буфер.
Механізм буферізації дозволяє швидше і ефективно обмінюватися інформацією із зовнішніми пристроями.
Для підтримки потоків бібліотека .NET містить ієрархію класів, основна частина якої представлена на рис. 11.1. Ці класи визначені в просторі імен System.IO. Окрім класів там описана велика кількість перелічень для завдання різних властивостей і режимів.
Класи бібліотеки дозволяють працювати в різних режимах з файлами, каталогами і областями оперативної пам'яті. Короткий опис класів приведений в таблиці 11.1.
Як можна бачити з таблиці, виконувати обмін із зовнішніми пристроями можна на рівні:
- двійкового представлення даних (BinaryReader, BinaryWriter);
- байтів (FileStream);
- тексту, тобто символів (StreamWriter, StreamReader).
У .NET використовується кодування Unicode, в якому кожен символ кодується двома байтами. Класи, що працюють з текстом, є оболонками класів, що використовують байти, і автоматично виконують те, що кодується з байтів в символи і назад.
Рис. 11.1. Класи бібліотеки .NET для роботи з потоками
Двійкові і байтові потоки зберігають дані в тому ж вигляді, в якому вони представлені в оперативній пам'яті, тобто при обміні з файлом відбувається побітове копіювання інформації. Двійкові файли застосовуються не для перегляду їх людиною, а для використання в програмах.
Доступ до файлів може бути послідовним, коли черговий елемент можна прочитати (записати) тільки після аналогічної операції з попереднім елементом, і довільним, або прямим, при якому виконується читання (запис) довільного елементу за заданою адресою. Текстові файли дозволяють виконувати тільки послідовний доступ, в двійкових і байтових потоках можна використовувати обидва методи.
Прямий доступ у поєднанні з відсутністю перетворень забезпечує високу швидкість отримання потрібної інформації.
Методи форматованого введення, за допомогою яких можна виконувати введення з клавіатури або з текстового файлу значень арифметичних типів, в С# не підтримуються. Для перетворення з символьного в числове представлення використовуються методи класу Convert або метод Parse, розглянуті в попередніх розділах.
Таблиця 11.1
Основні класи простору імен System.IO
Клас
| Опис
|
BinaryReader, BinaryWriter
| Читання і запис значень простих вбудованих типів (цілочисельних, логічних, рядкових і т. п.) у внутрішній формі уявлення
|
BufferedStream
| Тимчасове зберігання потоку байтів (наприклад, для подальшого перенесення в постійне сховище)
|
Directory, Directorylnfo, File, Filelnfo
| Робота з каталогами або фізичними файлами: створення, видалення, придбання властивостей. Можливості класів File і Directory реалізовані в основному у вигляді статичних методів. Аналогічні класи DirectoryInfo і FileInfo використовують звичайні методи
|
FileStream
| Довільний (прямий) доступ до файлу, представленого як потік байтів
|
MemoryStream
| Довільний доступ до потоку байтів в оперативній пам'яті
|
StreamWriter,
StreamReader
| Читання з файлу і запис у файл текстової інформації
(довільний доступ не підтримується)
|
StringWriter, StringReader
| Робота з текстовою інформацією в оперативній пам'яті
|
Форматоване виведення, тобто перетворення з внутрішньої форми представлення числа в символьну, зрозумілу людині, виконується за допомогою перевантажених методів ToString.
Окрім перерахованих класів в бібліотеці .NET є класи XmlTextReader і XmlTextWriter, призначені для формування і читання коду у форматі XML.
Розглянемо прості способи роботи з файловими потоками. Використання класів файлових потоків в програмі припускає наступні операції:
1. Створення потоку і зв’язування його з фізичним файлом.
2. Обмін (уведення-виведення).
3. Закриття файлу.
Кожен клас файлових потоків містить декілька варіантів конструкторів, за допомогою яких можна створювати об'єкти цих класів різними способами і в різних режимах.
Наприклад, файли можна відкривати тільки для читання, тільки для запису або для читання і запису. Ці режими доступу до файлу містяться в переліченні FileAccess, визначеному в просторі імен System. IO. Константи перелічення приведені в таблиці 11.2.
Таблиця 11.2
Значення FileAccess
Значення
| Опис
|
Read
| Відкрити файл тільки для читання
|
ReadWrite
| Відкрити файл для читання і запису
|
Write
| Відкрити файл тільки для запису
|
Можливі режими відкриття файлу визначені в переліченні FileMоdе (таблиця. 11.3).
Таблиця 11.3
Значення FilеМоdе
Значення
| Опис
|
Append
| Відкрити файл, якщо він існує, і встановити поточний покажчик в кінець файлу. Якщо файл не існує, створити новий файл
|
Create
| Створити новий файл. Якщо в каталозі вже існує файл з таким же ім'ям, він буде стертий
|
CreateNew
| Створити новий файл. Якщо в каталозі вже існує файл з таким же ім'ям, виникає виключення IOEхсерtion
|
Open
| Відкрити існуючий файл
|
OpenOrCreate
| Відкрити файл, якщо він існує. Якщо немає, створити файл з таким ім'ям
|
Truncate
| Відкрити існуючий файл. Після відкриття вміст файлу видаляється
|
Режим FileMode.Append можна використовувати тільки спільно з доступом типу FileAccess.Write, тобто для файлів, що відкриваються для запису.
Режими сумісного використання файлу різними користувачами визначає перелічення FileShare (таблиця 11.4).
Таблиця 11.4
Значення FileShare
Значення
| Опис
|
None
| Сумісне використання відкритого файлу заборонене. Запит на відкриття даного файлу завершується повідомленням про помилку
|
Read
| Дозволяє відкривати файл для читання одночасно декільком користувачам. Якщо цей прапор не встановлений, запити на відкриття файлу для читання завершуються повідомленням про помилку
|
ReadWrite
| Дозволяє відкривати файл для читання і запису одночасно декільком користувачам
|
Write
| Дозволяє відкривати файл для запису одночасно декільком користувачам
|