1. Кодування за замовчуванням
Коли ви працюєте зі StreamReader або StreamWriter, вони використовують кодування за замовчуванням.
Якщо ви пишете:
using var reader = new StreamReader("myfile.txt");
або
using var writer = new StreamWriter("output.txt");
.NET обирає кодування за замовчуванням. У Windows це зазвичай UTF-8 (часто без BOM), але в старих застосунках або під час запуску на інших системах поведінка може відрізнятися.
У більшості випадків UTF-8 — вдалий вибір: він підтримує всі мови й компактно зберігає англомовний текст (а також тексти багатьма європейськими мовами). Але якщо файл створений в іншому кодуванні (наприклад, у Windows-1251) або його читатимуть інші програми, які очікують певне кодування, вам слід явно вказати потрібне кодування.
2. Вказання кодування для StreamReader і StreamWriter
Варіанти конструкторів
І StreamReader, і StreamWriter підтримують конструктори, до яких можна передати об’єкт типу System.Text.Encoding.
Приклад:
using var reader = new StreamReader("myfile.txt", Encoding.UTF8);
using var writer = new StreamWriter("output.txt", false, Encoding.UTF8);
Якщо хочете працювати з ASCII, Windows-1251 або UTF-16, просто підставте інше кодування:
using var reader = new StreamReader("myfile.txt", Encoding.Unicode); // UTF-16
using var reader2 = new StreamReader("rus.txt", Encoding.GetEncoding("windows-1251"));
Коротка таблиця популярних кодувань:
| Кодування | C#-вираз | Опис |
|---|---|---|
| UTF-8 | |
Підтримує всі мови, компактне |
| UTF-16 (Unicode) | |
Стандарт .NET, 2 байти на символ |
| ASCII | |
Лише базові символи (англ.) |
| Windows-1251 | |
Кирилиця; старі програми для Windows |
Увага! Для нестандартних кодувань на кшталт Windows-1251 використовуйте метод Encoding.GetEncoding("windows-1251").
3. Читаємо і пишемо з вказанням кодування
Додаймо до нашого мінізастосунку новий функціонал: нехай він читає файл у вказаному кодуванні й записує результат до нового файлу, теж із явно заданим кодуванням. Так можна, наприклад, конвертувати текст між різними системами!
Приклад 1: Читання файлу у кодуванні Windows-1251 і виведення на екран
// Припустімо, файл створено в кодуванні Windows-1251
using var reader = new StreamReader("ru_text.txt", Encoding.GetEncoding("windows-1251"));
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
Чому це важливо: Якби ми не вказали кодування, замість кириличних літер отримали б жахливі символи типу "Учебник".
Приклад 2: Запис файлу в UTF-16 (Unicode)
using var writer = new StreamWriter("utf16text.txt", false, Encoding.Unicode);
writer.WriteLine("Привіт, світ!");
writer.WriteLine("Hello, world!");
writer.WriteLine("こんにちは世界");
Результат: Відкривши файл, наприклад, у Notepad, ви побачите, що всі символи чудово відображаються.
4. Невеличка утиліта для конвертації кодувань
Завдання (його часто ставлять на співбесідах!): Перетворити текстовий файл із кодування Windows-1251 у UTF-8.
string sourcePath = "ru_text_1251.txt";
string destPath = "ru_text_utf8.txt";
// Читаємо у кодуванні Windows-1251
using var reader = new StreamReader(sourcePath, Encoding.GetEncoding("windows-1251"));
// Записуємо у UTF-8
using var writer = new StreamWriter(destPath, false, Encoding.UTF8);
string? line;
while ((line = reader.ReadLine()) != null)
writer.WriteLine(line);
Тепер ru_text_utf8.txt можна без проблем відкривати у Visual Studio Code, у Linux, на Mac і бачити читабельний текст.
5. Корисні нюанси
Як дізнатися, у якому кодуванні файл?
Це запитання з підступом! Сам файл зазвичай не містить усередині інформацію про своє кодування (виняток — файли з BOM, про це детальніше в наступній лекції). Якщо ви відкриваєте файл у неправильному кодуванні, результат — каракулі.
Типові практичні підходи:
- Якщо файл був створений вашою програмою — завжди використовуйте те саме кодування для читання, що й під час запису.
- Якщо файл прийшов з невідомого джерела — спробуйте різні кодування або скористайтеся сторонніми утилітами, щоб його визначити.
Робота з емодзі та незвичними символами
UTF-8 і UTF-16 дозволяють вільно використовувати емодзі та символи з різних мов світу. Спробуйте зберегти файл з емодзі у UTF-8, а потім відкрити його в застарілому кодуванні — буде весело (або й ні)!
Код із емодзі:
using var writer = new StreamWriter("emoji.txt", false, Encoding.UTF8);
writer.WriteLine("Привіт 👋😀🌍");
StreamReader з автоматичним визначенням кодування
Конструктор StreamReader має перевантаження з параметром detectEncodingFromByteOrderMarks:
new StreamReader(path, encoding, detectEncodingFromByteOrderMarks: true)
Якщо цей параметр дорівнює true (це значення за замовчуванням!), StreamReader намагатиметься визначити кодування файлу за наявністю BOM (спеціальної «мітки» на початку файлу). Але якщо файл створено без BOM або в екзотичному кодуванні, визначення може не спрацювати.
Коли і навіщо варто явно вказувати кодування?
- Багатомовні дані: підтримка арабської, китайської, емодзі тощо.
- Інтеграції: файл читається/записується не лише вашою програмою, а й сторонньою системою, яка очікує певне кодування.
- Розмір файлу важливий: ASCII/UTF-8 економніші для латиниці, UTF-16 — для ієрогліфів.
- Сумісність: журнали/експорт для інших застосунків.
6. Типові помилки під час роботи з кодуваннями
Помилка № 1: відсутність явного вказання кодування під час читання файлу.
Читання файлу з нелатинським текстом без вказання кодування часто призводить до незрозумілої «абракадабри».
Помилка № 2: невідповідність кодувань під час запису та читання.
Файл було записано в одному кодуванні, а відкрито в іншому — у результаті отримуємо спотворений текст. Часто це трапляється під час перенесення між різними ОС чи програмами.
Помилка № 3: непідтримувані або частково підтримувані кодування.
Деякі редактори некоректно працюють з UTF-8 без BOM або зі старими однобайтовими кодуваннями, такими як Windows-1251. Іноді доводиться вручну перемикати кодування і експериментувати.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ