23

Как получить согласованное побайтовое представление строк в C# без ручного задания кодировки?

17

Как мне преобразовать строку в byte[] в .NET (C#) без явного указания конкретной кодировки?

Я собираюсь зашифровать строку. Я могу зашифровать её без преобразования, но мне всё равно хотелось бы понять, почему кодировка здесь важна.

Также, почему кодировку вообще стоит учитывать? Разве нельзя просто получить те байты, в которых строка хранится? Почему существует зависимость от кодировок символов?

5 ответ(ов)

19

В противоречии с ответами здесь, вам не нужно беспокоиться об编码ировании, если байты не требуют интерпретации!

Как вы упомянули, ваша цель - просто "получить, в каких байтах хранится строка".

(И, конечно, иметь возможность восстановить строку из байтов.)

Для этих целей я искренне не понимаю, почему люди продолжают говорить вам, что вам нужно беспокоиться о кодировках. Вам определенно не нужно беспокоиться о кодировках для этого.

Просто сделайте так:

static byte[] GetBytes(string str)
{
    byte[] bytes = new byte[str.Length * sizeof(char)];
    System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
    return bytes;
}

// НИКОГДА не используйте на произвольных байтах; используйте только выход GetBytes на ТОМ ЖЕ компьютере
static string GetString(byte[] bytes)
{
    char[] chars = new char[bytes.Length / sizeof(char)];
    System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
    return new string(chars);
}

Пока ваша программа (или другие программы) не пытаются каким-либо образом интерпретировать байты, что, очевидно, вы не упоминали, что собираетесь делать, то с этим подходом нет ничего плохого! Беспокойство о кодировках только усложняет вашу жизнь без реальной причины.

Дополнительное преимущество этого подхода: не имеет значения, содержит ли строка недопустимые символы, потому что вы все равно можете получить данные и восстановить исходную строку!

Она будет закодирована и декодирована так же, потому что вы просто смотрите на байты.

Если бы вы использовали конкретную кодировку, это могло бы вызвать проблемы с кодированием/декодированием недопустимых символов.

3

Принятый ответ действительно очень сложен. Используйте встроенные классы .NET для решения этой задачи:

const string data = "Строка с международными символами: Норвежский: ÆØÅæøå, Китайский: 喂 谢谢";
var bytes = System.Text.Encoding.UTF8.GetBytes(data);
var decoded = System.Text.Encoding.UTF8.GetString(bytes);

Не изобретайте велосипед, если в этом нет необходимости...

1

В вашем коде вы используете BinaryFormatter для сериализации и десериализации строки с использованием MemoryStream. Для начала, давайте разберем ключевые моменты:

  1. Вы создаете строку, содержащую как английские, так и китайские символы. Эта строка будет сериализована с помощью BinaryFormatter.

  2. После сериализации вы получаете массив байтов и отображаете его длину, а также длину оригинальной строки.

  3. Вы применяете простую "псевдошифровку" к массиву байтов, XOR'я их с числом 168. После этого вы снова применяете то же самое для декодирования, что позволяет восстановить оригинальные байты.

  4. Далее происходит десериализация полученного массива байтов обратно в строку. Вы подтверждаете, что строка осталась "нетронутой".

  5. В конце, вы сериализуете десериализованную строку вновь, чтобы показать, что длина полученного массива байтов все еще сохраняется.

Обратите внимание, что BinaryFormatter считается устаревшим и небезопасным для десериализации данных от непроверенных источников из-за уязвимостей безопасности. Рассмотрите возможность использования других методов сериализации, таких как System.Text.Json или XmlSerializer, в зависимости от ваших требований.

Пример вашего кода значительно иллюстрирует работу с байтовыми массивами и сериализацию/десериализацию объектов, но будьте осторожны с вопросами безопасности, если вы планируете использовать подобный подход в настоящем приложении.

0

Первая часть вашего вопроса (как получить байты) уже была ответена другими: обратитесь к пространству имен System.Text.Encoding.

Теперь я отвечу на ваш дополнительный вопрос: зачем вам нужно выбирать кодировку? Почему нельзя просто получить это из самого класса строки?

Ответ состоит из двух частей.

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

Если ваша программа полностью находится в мире .NET, тогда вам не нужно беспокоиться о получении массивов байтов для строк, даже если вы передаете данные по сети. Вместо этого используйте сериализацию .NET, чтобы сосредоточиться на передаче данных. Вам больше не нужно беспокоиться о фактических байтах: форматировщик сериализации делает это за вас.

С другой стороны, что если вы отправляете эти байты куда-то, откуда не можете гарантировать, что данные будут извлечены из сериализованного потока .NET? В этом случае вам действительно нужно беспокоиться о кодировке, потому что, очевидно, это внешней системе важно. Так что опять же, внутренние байты, используемые строкой, не важны: вам нужно выбрать кодировку, чтобы быть явным в отношении этой кодировки на принимающей стороне, даже если это та же самая кодировка, используемая внутри .NET.

Я понимаю, что в этом случае вы можете предпочесть использовать фактические байты, хранящиеся в переменной строки в памяти, поскольку это может сократить работу по созданию вашего байтового потока. Тем не менее, я считаю, что это просто не так важно по сравнению с тем, чтобы гарантировать, что ваш вывод будет понятен на другой стороне, и что вы должны быть явными в выборе вашей кодировки. Более того, если вы действительно хотите сопоставить ваши внутренние байты, вы можете просто выбрать кодировку Unicode и получить эту экономию производительности.

Это подводит меня ко второй части... выбор кодировки Unicode и есть указание .NET использовать базовые байты. Вам необходимо выбрать эту кодировку, потому что, когда появится новая кодировка Unicode-Plus, среда выполнения .NET должна иметь возможность использовать эту новую, улучшенную модель кодирования, не ломая вашу программу. Но на данный момент (и в обозримом будущем) просто выбор кодировки Unicode даст вам то, что вы хотите.

Также важно понимать, что ваша строка должна быть переписана для передачи по сети, и это включает в себя по меньшей мере некоторую трансляцию битового паттерна даже если вы используете совпадающую кодировку. Компьютер должен учитывать такие вещи, как порядок байтов Big Endian против Little Endian, сетевая порядок байтов, пакетизация, информация о сессии и т.д.

0

Попробуйте так, это гораздо меньше кода:

System.Text.Encoding.UTF8.GetBytes("TEST String");

Этот код преобразует строку "TEST String" в массив байтов, используя кодировку UTF-8.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь