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 | |
Поддержка всех языков, compact |
| 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 можно спокойно открывать в VSCode, 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. Иногда приходится вручную переключать кодировку и экспериментировать.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ