1. Вступ
StreamWriter — один із ключових класів простору імен System.IO у .NET, призначений для зручного запису текстових даних у файли через потік.
Чому не можна одразу працювати з FileStream?
FileStream працює лише з байтами. Якщо спробувати записати рядок через нього, доведеться самостійно перетворювати текст на байти та враховувати кодування (потім ви точно захочете повернутися до StreamWriter).
StreamWriter бере на себе всі ці турботи: ви передаєте йому рядок — він записує потрібні байти у файл.
Основні переваги:
- Легко записувати рядки, не замислюючись над перетворенням на байти.
- Є методи для пострядкового запису тексту.
- Керування буферизацією та кодуванням (ми ще навчимося цим користуватися).
Найпростіший приклад
using System.IO;
string path = "output.txt";
using (StreamWriter writer = new StreamWriter(path))
{
writer.WriteLine("Привіт, світ!");
writer.WriteLine("Це другий рядок.");
}
// Після виходу з блоку using StreamWriter гарантовано звільнить файл.
Що тут відбувається?
- Відкривається файл для запису (якщо файла немає — його буде створено).
- Кожен виклик записує окремий рядок у файлі (метод WriteLine).
- Після блоку using файл автоматично закривається, навіть якщо виникнуть помилки.
Якщо відкрити файл output.txt після виконання цієї програми, ви побачите два рядки тексту — саме так, як і очікувалося.
Важливий нюанс
Якщо файл уже існує, його буде перезаписано з нуля! Усе, що було всередині, — зникне. Тому обережно: не зберігайте у таких файлах важливу дисертацію чи єдиний примірник квитанції за комунальні послуги.
2. Запис даних у потік
Головні методи StreamWriter
| Метод | Опис |
|---|---|
|
Записує рядок без переходу на новий рядок. |
|
Записує рядок із переходом на новий рядок. |
|
Примусово скидає буфер у файл (вручну потрібно рідко). |
/ |
Закриває потік і звільняє ресурси (те саме робить using). |
|
Отримати доступ до базового потоку (наприклад, FileStream). |
Метод Write()
Записує дані без переходу на новий рядок. Усе, що ви запишете далі, буде в тому самому рядку файлу.
Метод WriteLine()
Записує дані з автоматичним додаванням символу кінця рядка (\r\n у Windows, \n у Unix-подібних ОС).
Це ніби натискати клавішу Enter після кожного запису.
Write() vs WriteLine(): демонстрація різниці
using (var writer = new StreamWriter("example.txt"))
{
writer.Write("Перший ");
writer.Write("абзац. ");
writer.WriteLine("Дописали рядок, Enter!");
writer.Write("Другий абзац.");
}
Тепер example.txt буде виглядати приблизно так:
Перший абзац. Дописали рядок, Enter!
Другий абзац.
3. Робота з кодуваннями
За замовчуванням при створенні StreamWriter без указання параметрів буде використано кодування UTF-8 з BOM (Byte Order Mark).
На практиці це зручно й сучасно, але бувають випадки, коли потрібно явно вказати кодування — наприклад, для сумісності зі старими програмами чи імпортованими даними.
Як вказати кодування?
// Запис файлу у кодуванні Windows-1251 (кирилиця для застарілих систем)
using (var writer = new StreamWriter("cyrillic.txt", false, System.Text.Encoding.GetEncoding("windows-1251")))
{
writer.WriteLine("Привіт, кириличний світ!");
}
Важливий момент:
Кодування має підтримуватися на системі. Якщо не впевнені — використовуйте UTF-8.
4. Додаткові параметри конструктора
Зазирнімо до внутрішньої кухні StreamWriter:
public StreamWriter(
string path, // шлях до файлу
bool append = false, // дописувати у кінець файлу?
Encoding encoding = null, // кодування
int bufferSize = 1024 // розмір буфера, у байтах
)
- append — якщо false (за замовчуванням), файл буде перезаписаний. Якщо true, нові записи будуть додані у кінець.
- encoding — використовуване кодування.
- bufferSize — розмір внутрішнього буфера для прискорення роботи з великими обсягами даних.
Приклад: дозапис у той самий файл
// Файл буде доповнюватися, а не перезаписуватися
using (var writer = new StreamWriter("log.txt", append: true))
{
writer.WriteLine(DateTime.Now + " -- Нова подія");
}
5. Корисні нюанси
Що відбувається при дозапису та перезапису
| Режим | Що робить? | Результат у файлі |
|---|---|---|
| append: false | Перезаписує все начисто | Старі дані стираються |
| append: true | Додає нові рядки у кінець | Старі рядки зберігаються |
Підказка: Режим дозапису (append: true) — оптимальний вибір для логування, коли потрібно зберігати історію подій.
StreamWriter і великі обсяги даних
- StreamWriter буферизує запис: фактичні дані потрапляють у файл трохи пізніше, ніж ви викликали WriteLine. Але після закриття потоку (або виклику Flush()) усе гарантовано опиниться на диску.
- Запис через WriteLine дуже ефективний для пострядкового виведення. Для складних форматів (JSON, CSV чи XML) краще використовувати відповідні бібліотеки або ретельно екранувати спеціальні символи (наприклад, коми чи лапки).
Як правильно завершувати запис і звільняти ресурси
Правильний спосіб: завжди використовуйте using!
Так ви гарантуєте, що файл закриється, навіть якщо станеться виняток (наприклад, якщо раптово «закінчився» простір на диску чи файл заблокувала інша програма).
6. Практичні приклади
Припустімо, у межах курсу в нас є мініпрограма обліку книжок. Додамо функціональність запису нових книжок у файл.
Приклад: Зберігаємо нову книжку в окремий файл
using System;
using System.IO;
class Program
{
static void Main()
{
Console.WriteLine("Введіть назву книжки:");
string bookTitle = Console.ReadLine();
Console.WriteLine("Введіть автора:");
string author = Console.ReadLine();
string path = "books.txt";
using (var writer = new StreamWriter(path, append: true))
{
writer.WriteLine($"{bookTitle};{author}");
// Формат CSV: кожен рядок - окрема книжка, через крапку з комою
}
Console.WriteLine("Книжку збережено у файлі!");
}
}
Спробуйте додати кілька книжок підряд. У файлі books.txt рядки додаватимуться, не стираючи попередні. Така поведінка зручна для ведення логів чи журналів — наприклад, для вашої майбутньої системи аудиту, коли ви доростете до Enterprise-розробника.
7. Як уникнути типових помилок при записі у файл
Більшість новачків стикається з такими труднощами:
Файл не закрито й заблоковано іншим процесом. Причина — забули про using.
Записали багато рядків, але файл залишився порожнім: забули викликати Flush() або закрити потік (а з using це робиться автоматично).
Неочікувано перезаписали файл замість дозапису — забули вказати append: true.
Проблеми з кодуванням: файл відкривається з некоректними символами у «Блокноті» — вибрано не те кодування або інша програма не підтримує UTF-8.
Виняток UnauthorizedAccessException або DirectoryNotFoundException: програма намагається зберегти файл туди, де в неї немає прав, або в неіснуючу папку. Перевірте шлях і права доступу.
Помилка «file is used by another process»: ви відкрили файл на запис, але не закрили його, або паралельно хтось інший намагається записати туди ж.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ