Превращаем строку в массив байтов в C#: полное руководство

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

«Строки» и «байты»: почему это вечная головная боль программиста?

Представьте себе ситуацию: вы пишете на C# сетевое приложение, отправляете данные на сервер, а на выходе — каша из символов. Или шифруете пароль, а на другом конце его не могут расшифровать. Знакомо? Корень зла часто кроется в неправильном преобразовании строки в массив байтов (и обратно).

Вопрос «Converting string to byte array in C#» на Stack Overflow собрал тысячи просмотров не случайно. Это база, на которой держатся работа с файлами, криптография, сериализация и сетевое взаимодействие. Без понимания этой темы вы будете наступать на одни и те же грабли. Давайте раз и навсегда разберемся, как делать это правильно.

Почему нельзя просто взять и преобразовать строку в байты?

Наивный подход — использовать BitConverter.GetBytes() для символа? Нет. Проблема в том, что строка — это абстракция, состоящая из символов (char, 2 байта в C#). А массив байтов — это сырые данные, которые зависят от кодировки.

Один и тот же символ «A» в кодировке UTF-8 займет 1 байт, в UTF-16 — 2 байта, а в UTF-32 — 4 байта. Если вы выберете не ту кодировку, данные будут потеряны. Запомните главное правило: всегда указывайте кодировку явно.

Самый популярный метод: Encoding.UTF8.GetBytes()

Это то, что вы будете использовать в 90% случаев. UTF-8 — стандарт де-факто для веба, JSON и большинства API.

using System;
using System.Text;

class Program
{
    static void Main()
    {
        string original = "Привет, мир! 🌍";
        
        // Преобразуем строку в массив байтов (UTF-8)
        byte[] utf8Bytes = Encoding.UTF8.GetBytes(original);
        
        // Обратное преобразование (для проверки)
        string restored = Encoding.UTF8.GetString(utf8Bytes);
        
        Console.WriteLine($"Исходная строка: {original}");
        Console.WriteLine($"Массив байтов (длина {utf8Bytes.Length}): {BitConverter.ToString(utf8Bytes)}");
        Console.WriteLine($"Восстановленная строка: {restored}");
    }
}

Результат работы:

Исходная строка: Привет, мир! 🌍
Массив байтов (длина 18): D0-9F-D1-80-D0-B8-D0-B2-D0-B5-D1-82-2C-20-D0-BC-D0-B8-D1-80-21-20-F0-9F-8C-8D
Восстановленная строка: Привет, мир! 🌍

Обратите внимание: эмодзи «🌍» занимает 4 байта (F0-9F-8C-8D). UTF-8 умеет работать с любыми символами Юникода, в отличие от устаревших кодировок.

Другие популярные кодировки

  • Encoding.ASCII — только 7-битные символы (0-127). Для кириллицы или спецсимволов не подходит — все, что выше 127, превратится в '?'
  • Encoding.Unicode (он же UTF-16LE) — используется внутри C# для хранения строк. Каждый символ занимает 2 байта (или 4 для суррогатных пар).
  • Encoding.UTF32 — каждый символ строго 4 байта. Ресурсоёмко, но предсказуемо.
  • Encoding.Default — системная кодировка (ANSI). Избегайте! Она разная на разных компьютерах.

Преобразование с помощью BitConverter и MemoryStream

Иногда нужно получить «сырое» представление строки как массива символов (char). Это не то же самое, что байты в кодировке, но бывает полезно для низкоуровневой работы.

string text = "C#";
// Получаем массив char
char[] chars = text.ToCharArray();
// Конвертируем каждый char в 2 байта (Little-Endian)
byte[] rawBytes = new byte[chars.Length * sizeof(char)];
Buffer.BlockCopy(chars, 0, rawBytes, 0, rawBytes.Length);

Console.WriteLine(BitConverter.ToString(rawBytes)); // 43-00-23-00

Этот метод даёт массив в кодировке UTF-16LE (как хранится в памяти). Используйте его только если точно знаете, что делаете.

Специальный случай: Base64

Если вам нужно передать массив байтов в виде текста (например, в JSON или URL), используйте Base64. Это не кодировка символов, а способ представления двоичных данных.

string input = "Hello, C#!";
byte[] bytes = Encoding.UTF8.GetBytes(input);

// В Base64
string base64 = Convert.ToBase64String(bytes);
Console.WriteLine(base64); // SGVsbG8sIEMh

// Обратно
byte[] decodedBytes = Convert.FromBase64String(base64);
string output = Encoding.UTF8.GetString(decodedBytes);
Console.WriteLine(output); // Hello, C#!

Base64 увеличивает размер данных на ~33%, но гарантирует, что они не будут повреждены при передаче через текстовые протоколы.

Типичные ошибки (и как их избежать)

Ошибка #1: Забыли про кодировку

// ПЛОХО: результат зависит от культуры системы
byte[] badBytes = Encoding.Default.GetBytes("строка");

Решение: Всегда указывайте Encoding.UTF8 или другую явную кодировку.

Ошибка #2: Путаница между char и byte

// ПЛОХО: char это 2 байта, а не 1
byte singleByte = (byte)'Я'; // Потеря данных!

Решение: Используйте Encoding для корректного преобразования.

Ошибка #3: Неправильная кодировка при обратном преобразовании

byte[] bytes = Encoding.UTF8.GetBytes("Привет");
// ОШИБКА: пытаемся декодировать как ASCII
string broken = Encoding.ASCII.GetString(bytes); // "??????"

Решение: Кодировка при декодировании должна совпадать с той, что использовалась при кодировании.

Продвинутая техника: свой кастомный конвертер

Если вы часто работаете с разными кодировками, создайте утилитарный класс:

public static class StringByteConverter
{
    public static byte[] ToBytes(this string str, Encoding encoding = null)
    {
        encoding ??= Encoding.UTF8;
        return encoding.GetBytes(str ?? string.Empty);
    }

    public static string FromBytes(this byte[] bytes, Encoding encoding = null)
    {
        encoding ??= Encoding.UTF8;
        return encoding.GetString(bytes ?? Array.Empty<byte>());
    }
}

// Использование
string message = "Кодируем с запасом";
byte[] data = message.ToBytes(); // UTF-8 по умолчанию
string decoded = data.FromBytes(Encoding.Unicode); // О                

Блоги

Рекомендаций по книгам