TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.77K subscribers
Post #1234 1.45K
День 1007. #TipsAndTricks
Как не Стоит Читать Строку из Потока UTF-8
Пост возник после код ревью. Следующий код читает из потока строку в кодировке UTF-8. В реальном контексте код сложнее, здесь только суть:
string ReadString(Stream stream)
{
var sb = new StringBuilder();
var buf = new byte[4096];
int readCnt;
while ((readCnt = stream.Read(buf)) > 0)
{
var s = Encoding.UTF8
.GetString(buffer, 0, readCnt);
sb.Append(s);
}

return sb.ToString();
}

Проблема в том, что в некоторых случаях возвращаемая строка отличается от закодированной. Например, иногда смайлик превращается в 4 неизвестных символа:
В потоке: 😊
В результате: ????

UTF-8 может использовать от 1 до 4 байт для представления символа, но метод Stream.Read может возвращать байты от 1 до buffer.Length. Это означает, что буфер может содержать неполный символ UTF-8. В результате Encoding.UTF8.GetString может иметь недопустимую строку UTF-8 для преобразования, поскольку последний символ в буфере может быть неполным. Следующий код имитирует это поведение:
var bytes = Encoding.UTF8.GetBytes("😊");
// bytes = new byte[4] { 240, 159, 152, 138 }

var sb = new StringBuilder();
// Симулируем побайтовое чтение
for (var i = 0; i < bytes.Length; i++)
{
sb.Append(Encoding.UTF8.GetString(bytes, i, 1));
}

Console.WriteLine(sb.ToString());
// "????" вместо "😊"

Encoding.UTF8.GetBytes(sb.ToString());
// new byte[12] { 239, 191, 189, 239, 191, 189, 239, 191, 189, 239, 191, 189 }

Есть несколько способов исправить код.

Один из них - преобразовать массив байт в строку только тогда, когда у вас есть все данные:
string ReadString(Stream stream)
{
using var ms = new MemoryStream();
var buf = new byte[4096];
int readCnt;
while ((readCnt = stream.Read(buf)) > 0)
ms.Write(buf, 0, readCnt);

return
Encoding.UTF8.GetString(ms.ToArray());
}

Вы также можете обернуть поток в StreamReader с правильной кодировкой:
string ReadString(Stream stream)
{
using var sr =
new StreamReader(stream, Encoding.UTF8);
return sr.ReadToEnd();
}

Источник: https://www.meziantou.net/how-not-to-read-a-string-from-an-utf-8-stream.htm
More from @netdeveloperdiary
  1. Oct 17, 2026День 2817. #ЧтоНовенького #VS Прекращаем Сборку После Первой Ошибки Мэдс Кристенсен продол…
  2. Oct 16, 2026День 2816. #Карьера #AI Станет ли ИИ-Кодинг Концом Программирования для Людей? Автор ориги…
  3. Oct 15, 2026Post #3374
  4. Oct 14, 2026Post #3373
  5. Oct 13, 2026День 2813. #ЗаметкиНаПолях #Async Ещё Раз Про Async/Await в C#. Часть 1 Почему существует…
  6. Oct 12, 2026День 2812. #Карьера #AI Как Разработчикам Оставаться Полезными, Когда Код Пишет ИИ? По мер…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →