Підрозділ 18.3
Stream та FileStream. Потоковий доступ до файлів
18.3. Stream та FileStream. Потоковий доступ до файлів Усі класи File.WriteAllText , File.ReadAllBytes — це зручні обгортки над нижчим рівнем абстракції: потоками streams . Потік — це абстракція послідовного до
18.3. Stream та FileStream. Потоковий доступ до файлів
Усі класи File.WriteAllText, File.ReadAllBytes — це зручні обгортки над нижчим рівнем абстракції: потоками (streams). Потік — це абстракція послідовного доступу до даних, де читання або запис відбуваються по шматках (chunk by chunk), а не завантаженням усього ресурсу у пам'ять одразу. Розуміння потоків є фундаментом для роботи не лише з файлами, а й з мережевими з'єднаннями, ZIP-архівами, HTTP-відповідями, шифруванням — будь-яким I/O у .NET.
Абстрактний клас Stream визначає єдиний контракт для всіх видів потоків. FileStream — одна з конкретних реалізацій, що забезпечує потоковий доступ до файлів на диску.

Абстрактний клас Stream
Stream (простір імен System.IO) визначає мінімальний набір можливостей, якими може володіти або не володіти потік:
Stream визначає три типи операцій: читання (Read, ReadByte), запис (Write, WriteByte, Flush) і позиціонування (Seek, Position). Не всі потоки підтримують усі операції — мережевий потік NetworkStream не підтримує Seek (CanSeek == false), потік лише для читання не підтримує Write. Перевіряйте CanRead/CanWrite/CanSeek перед використанням.
Клас FileStream
FileStream — реалізація Stream для файлів на диску. Він підтримує всі три операції: читання, запис і позиціонування (CanSeek == true).
Відкриття файлу: FileMode та FileAccess
FileMode визначає, що відбувається при відкритті:
| FileMode | Якщо файл існує | Якщо файл не існує |
|---|---|---|
Create |
Обрізає до нуля | Створює новий |
CreateNew |
Кидає IOException | Створює новий |
Open |
Відкриває | Кидає FileNotFoundException |
OpenOrCreate |
Відкриває | Створює новий |
Append |
Відкриває, позиція в кінці | Створює новий |
Truncate |
Обрізає до нуля | Кидає FileNotFoundException |
Буферизований запис та Flush
Flush() гарантує, що буферизовані дані записані на фізичний диск. Для критичних даних (медичні журнали, транзакції) — викликайте Flush() після кожного запису. При звичайних ситуаціях using / Dispose автоматично виконає Flush і Close.
Паралельний доступ: FileShare
FileShare визначає, що дозволяється іншим процесам (або потокам) робити з файлом, поки він відкритий у вас:
| FileShare | Опис |
|---|---|
None |
Виключний доступ — ніхто інший не може відкрити файл |
Read |
Інші можуть відкривати для читання |
Write |
Інші можуть відкривати для запису |
ReadWrite |
Інші можуть відкривати для читання і запису |
Delete |
Інші можуть видаляти файл |
Читання та запис по шматках — ефективна обробка великих файлів
Ключова перевага потокового доступу — обробка файлів будь-якого розміру при константному використанні пам'яті:
Stream.CopyTo(Stream destination, int bufferSize) — вбудований метод для копіювання між будь-якими потоками: з файлу у файл, з файлу у мережу, з HTTP-відповіді у файл. Внутрішньо він теж читає по шматках вказаного розміру.
Seekable потік: довільний доступ до даних
Файлові потоки (CanSeek == true) підтримують довільний доступ — стрибок до будь-якої позиції за O(1). Це основа для баз даних фіксованих записів, індексних структур і форматів з заголовками.
MemoryStream — потік у пам'яті
MemoryStream реалізує Stream над масивом байтів у пам'яті. Не звертається до диску, але реалізує той самий інтерфейс. Корисний для тестування (замість реальних файлів), серіалізації у пам'яті та конвеєрів обробки:
leaveOpen: true у конструкторі StreamWriter — важливий параметр: без нього StreamWriter.Dispose() закриє і MemoryStream, і ми не зможемо прочитати дані після using-блоку.
Практичний сценарій: журнал медичних подій з FileStream
