JavaRush /Курси /C# SELF /Перекодування файлів

Перекодування файлів

C# SELF
Рівень 37 , Лекція 4
Відкрита

1. Вступ

Почнемо з головного питання — навіщо взагалі працювати з кодуваннями? Здавалося б: один файл, одне кодування — і все має бути спокійно. Але на практиці все складніше. Дуже швидко з’ясовується, що файл може надійти звідки завгодно й у цілком несподіваному кодуванні. А ваш застосунок, звісно, очікує зовсім іншого.

Іноді потрібно інтегруватися з певним API або системою, де жорстко задано: лише таке‑то кодування і жодне інше. Буває, дістаєте старий файл, якому років з десять, і намагаєтеся відкрити його в новому редакторі — а там «кракозябри». Або, наприклад, ви зберігаєте CSV‑звіт і хочете бути певні, що його зможуть нормально прочитати всі колеги — і на Windows, і на macOS, і навіть у Excel.

Отже, перекодування — це не рідкісне чи екзотичне явище. Навпаки, це дуже реальне й доволі часте завдання, яке трапляється будь‑де: під час вивантаження з баз даних, роботи з архівами, під час інтеграції з бухгалтерією або в автоматичних скриптах. І чим раніше з цим розібратися, тим менше потім буде несподіванок.

Від старого кодування до нового

Щоб перекодувати файл, потрібно виконати два кроки:

  1. Прочитати файл у початковому кодуванні, отримавши рядки (або символи).
  2. Записати рядки в новий файл, явно вказавши потрібне цільове кодування.

Аналогія: уявіть, що ви перекладаєте книжку з французької на українську. Спершу треба вміти читати французькою (прочитати текст), а потім — передати той самий зміст українською (записати текст українською).

У C# (і .NET) це робиться через встановлення відповідного об’єкта Encoding у конструкторі StreamReader (для читання) і StreamWriter (для запису).

Огляд кодувань і клас Encoding

Усі «магічні» перетворення символів виконуються за допомогою класу System.Text.Encoding.

Таблицю з основними кодуваннями та способами отримання їх у C# можна подати так:

Кодування Опис C# константа
UTF-8 Універсальне, без BOM за замовчуванням
Encoding.UTF8
UTF-8 з BOM Те саме, але з сигнатурою BOM
new UTF8Encoding(true)
UTF-16 (LE/BE) «wide char», little-endian Encoding.Unicode (LE),
Encoding.BigEndianUnicode (BE)
ASCII 7‑бітна класика
Encoding.ASCII
Windows-1251 Популярне для кирилиці
Encoding.GetEncoding(1251)
ISO-8859-1 Латиниця (європейська)
Encoding.GetEncoding("ISO-8859-1")

Примітка: Для старих кодувань доведеться використовувати Encoding.GetEncoding: іноді з номером (1251), іноді з рядком ("windows-1251").

2. Перекодування: покрокова стратегія в C#

Розберімося, як реалізувати перекодування на практиці.

Алгоритм

  1. Відкрити початковий файл через StreamReader, явно вказавши початкове кодування.
  2. Прочитати текст (цілком або построково — залежно від розміру файлу).
  3. Відкрити вихідний файл через StreamWriter, вказавши бажане кінцеве кодування.
  4. Записати текст у вихідний файл.
  5. Не забудьте закривати потоки — використовуйте using для надійності!

Приклад: перекодування Windows-1251 → UTF-8

Припустімо, маємо файл "input-1251.txt" у кодуванні Windows-1251, а хочемо "output-utf8.txt" у «чистому» UTF‑8 (без BOM).

// Вказуємо джерело з початковим кодуванням
using var reader = new StreamReader("input-1251.txt", Encoding.GetEncoding(1251));
using var writer = new StreamWriter("output-utf8.txt", false, Encoding.UTF8);

string line;
// Читаємо построково — зручно для великих файлів
while ((line = reader.ReadLine()) != null)
{
    writer.WriteLine(line);
}

Console.WriteLine("Файл успішно перекодовано з Windows-1251 у UTF-8!");

Такий код гарантує, що кожен рядок коректно перетвориться з одного кодування в інше.

Схематично це виглядає так:


┌───────────────────────────────┐     ┌───────────────────┐     ┌───────────────────────────────┐
│ Файл "input-1251.txt" (1251)  │ --> │  StreamReader     │ --> │  Рядки типу string у пам’яті  │
└───────────────────────────────┘     │ (Encoding 1251)   │     └───────────────────────────────┘
                                      └───────────────────┘
                                              │
                                              ▼
                                  ┌────────────────────────┐
                                  │   StreamWriter         │
                                  │   (Encoding UTF-8)     │
                                  └───────────┬────────────┘
                                            │
                                            ▼
                              ┌──────────────────────────────┐
                              │ "output-utf8.txt" (UTF-8)    │
                              └──────────────────────────────┘

3. Практичний приклад: конвертер кодувань

Ускладнімо завдання: напишемо просту програму‑конвертер, де користувач може самостійно обрати початковий і цільовий файл, а також кодування.

Console.WriteLine("Введіть шлях до вхідного файлу:");
string inputPath = Console.ReadLine();

Console.WriteLine("Кодування вхідного файлу (наприклад, 1251, utf-8):");
string sourceEncodingName = Console.ReadLine();

Console.WriteLine("Введіть шлях до цільового файлу:");
string outputPath = Console.ReadLine();

Console.WriteLine("Кодування для збереження (наприклад, utf-8, 1251):");
string destEncodingName = Console.ReadLine();

Encoding sourceEncoding = Encoding.GetEncoding(sourceEncodingName);
Encoding destEncoding = Encoding.GetEncoding(destEncodingName);

using var reader = new StreamReader(inputPath, sourceEncoding);
using var writer = new StreamWriter(outputPath, false, destEncoding);
string line;
while ((line = reader.ReadLine()) != null)
{
    writer.WriteLine(line);
}

Console.WriteLine("Готово! Перевірте результат.");

Порада: Якщо ви не впевнені, яке кодування вказати, перегляньте документацію або спробуйте різні варіанти. Іноді файл можна «впізнати» лише експериментально, якщо ніхто не лишив добрий README.

4. Важливі нюанси: BOM, «невидимі» символи та спецвипадки

Як додати BOM під час збереження UTF-8?

За замовчуванням Encoding.UTF8 у C# створює файли без BOM (Byte Order Mark). Якщо потрібно створити файл із BOM, використовуйте:

// true — означає «з BOM»
var utf8WithBom = new UTF8Encoding(true);

using var writer = new StreamWriter("with-bom.txt", false, utf8WithBom);
writer.WriteLine("Текст із BOM");

Файл тепер починатиметься з «невидимих» трьох байтів: 0xEF, 0xBB, 0xBF.

Коли BOM — зло?

  • Якщо експортуєте CSV для Excel, у багатьох версіях BOM лише заважає — з’являються дивні символи.
  • В Unix‑подібних системах (Linux) BOM інколи ламає обробку файлів.
  • Для JSON‑файлів BOM — майже завжди зло, багато парсерів не справляються!

Порада: Свідомо обирайте, чи потрібен BOM, і додавайте його лише за потреби.

Підступні символи й «магічні» числа

Якщо під час відкриття «перекодованого» файлу програма видає помилку формату, можливо, ви не врахували «невидимі» символи на початку файлу (наприклад, BOM) або помилилися з самим кодуванням (скажімо, прочитали файл як ASCII, а там — кирилиця у Windows-1251). Завжди звіряйте, які саме кодування використовують ваш застосунок, колеги або сервер.

5. Корисні деталі

Робота з великими файлами: чому построково, а не цілком?

Можна було б написати просто:

string allText = File.ReadAllText("input.txt", Encoding.GetEncoding(1251));
File.WriteAllText("output.txt", allText, Encoding.UTF8);

Цей підхід годиться для малих і середніх файлів (скажімо, до 50 МБ). Але якщо файл великий, увесь текст завантажиться в оперативну пам’ять — і якщо файл на кілька ГБ, будуть проблеми з пам’яттю. Тож для універсальності використовуємо построкове читання/запис.

Перекодування між менш поширеними кодуваннями

Припустімо, у вас раптом з’явився файл в ISO-8859-1 (так інколи налаштовані бази даних MySQL), а треба отримати його в Unicode.

var sourceEnc = Encoding.GetEncoding("iso-8859-1");
var destEnc = Encoding.UTF8;

using var reader = new StreamReader("data-latin.txt", sourceEnc);
using var writer = new StreamWriter("data-unicode.txt", false, destEnc);
string line;
while ((line = reader.ReadLine()) != null)
{
    writer.WriteLine(line);
}

Такий підхід працює з будь-яким кодуванням, якщо його підтримує .NET.

Перекодування бінарних файлів — не слід!

Програма, описана вище, призначена виключно для текстових файлів. Якщо файл — бінарний (наприклад, зображення, звуковий файл, архів), спроба «прочитати його як текст, а потім записати» гарантовано пошкодить байти, виведе «кракозябри», і файл стане непридатним. Для бінарних файлів перекодування не застосовується — «кодування» там узагалі не має сенсу.

Таблиця відповідностей: які кодування корисні для чого

Кодування Коли використовувати
UTF-8 Універсальні файли, web, сучасні застосунки
UTF-8 з BOM Для сумісності з Notepad, Excel
Windows-1251 Для спадкових або застарілих локальних програм
ASCII Для файлів, де є лише англійський текст
UTF-16 Для спеціальних випадків, екзотичні застосунки

Корисні дрібниці та поради

Як дізнатися кодування файлу?

  • Спеціалізовані редактори (Notepad++, Visual Studio Code) часто визначають і показують кодування.
  • Якщо немає BOM і все читається нібито нормально, але символи відображаються некоректно — найімовірніше, кодування не збіглося.

Чи можна автоматизувати визначення кодування?

  • У .NET немає «чарівної палички», яка на 100 % визначить кодування будь‑якого файлу. Зазвичай правило таке: якщо є BOM, це явно UTF із BOM; якщо немає — доводиться здогадуватися за вмістом або пробувати різні варіанти.

Що робити, якщо частина рядків читається нормально, а частина — «кракозябри»?

  • Можливо, файл змішаний або пошкоджений. Перевірте, чи файл не записувався різними програмами.

6. Типові помилки і як їх уникнути

Для кращого розуміння розгляньмо найпоширеніші помилки:

Неправильне початкове кодування. Якщо ви вважаєте, що файл у UTF-8, а він насправді у Windows-1251 — отримаєте «кракозябри» замість кирилиці. Перевіряйте початкове кодування; якщо не впевнені — відкрийте файл у Notepad++ чи схожих редакторах, що показують реальне кодування.

BOM не там, де потрібно. Іноді додавання BOM ламає парсинг, інколи відсутність BOM призводить до неправильного визначення кодування на стороні іншого ПЗ.

Читання всього файлу в пам’ять. Якщо файл великий, використовуйте построкове читання — інакше програма може «з’їсти» всю RAM під час роботи з великим текстовим файлом.

Запис без вказування кодування. За замовчуванням StreamWriter використовує UTF-8 без BOM. Якщо потрібен інший варіант — явно вкажіть кодування.

Неправильне використання GetEncoding. Якщо помилитися в рядку, наприклад, "utf8" замість "utf-8", отримаєте виняток. Використовуйте правильні назви (або коди, наприклад, 1251).

1
Опитування
Основні типи кодувань, рівень 37, лекція 4
Недоступний
Основні типи кодувань
Робота з кодуваннями файлів
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ