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

Как преобразовать string в byte[] в .NET(С#) без указания конкретной кодировки вручную?

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

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

Ответ 1

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

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

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

Просто сделайте это вместо этого:

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;
}

// Do NOT use on arbitrary bytes; only use on GetBytes output on the SAME system
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);
}

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

Дополнительное преимущество этого подхода:

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

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

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

Ответ 2

Это зависит от кодировки вашей строки (ASCII, UTF-8,...).

Например:

byte[] b1 = System.Text.Encoding.UTF8.GetBytes (myString);
byte[] b2 = System.Text.Encoding.ASCII.GetBytes (myString);

Небольшая выборка, почему кодирование имеет значение:

string pi = "\u03a0";
byte[] ascii = System.Text.Encoding.ASCII.GetBytes (pi);
byte[] utf8 = System.Text.Encoding.UTF8.GetBytes (pi);

Console.WriteLine (ascii.Length); //Will print 1
Console.WriteLine (utf8.Length); //Will print 2
Console.WriteLine (System.Text.Encoding.ASCII.GetString (ascii)); //Will print '?'

ASCII просто не оборудован для обработки специальных символов.

Внутри платформа .NET использует UTF-16 для представления строк, поэтому, если вы просто хотите получить точные байты, которые использует .NET, используйте System.Text.Encoding.Unicode.GetBytes (...).

Для получения дополнительной информации см. Кодировка символов в .NET Framework (MSDN).

Ответ 3

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

const string data = "A string with international characters: Norwegian: ÆØÅæøå, Chinese: 喂 谢谢";
var bytes = System.Text.Encoding.UTF8.GetBytes(data);
var decoded = System.Text.Encoding.UTF8.GetString(bytes);

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

Ответ 4

BinaryFormatter bf = new BinaryFormatter();
byte[] bytes;
MemoryStream ms = new MemoryStream();

string orig = "喂 Hello 谢谢 Thank You";
bf.Serialize(ms, orig);
ms.Seek(0, 0);
bytes = ms.ToArray();

MessageBox.Show("Original bytes Length: " + bytes.Length.ToString());

MessageBox.Show("Original string Length: " + orig.Length.ToString());

for (int i = 0; i < bytes.Length; ++i) bytes[i] ^= 168; // pseudo encrypt
for (int i = 0; i < bytes.Length; ++i) bytes[i] ^= 168; // pseudo decrypt

BinaryFormatter bfx = new BinaryFormatter();
MemoryStream msx = new MemoryStream();            
msx.Write(bytes, 0, bytes.Length);
msx.Seek(0, 0);
string sx = (string)bfx.Deserialize(msx);

MessageBox.Show("Still intact :" + sx);

MessageBox.Show("Deserialize string Length(still intact): " 
    + sx.Length.ToString());

BinaryFormatter bfy = new BinaryFormatter();
MemoryStream msy = new MemoryStream();
bfy.Serialize(msy, sx);
msy.Seek(0, 0);
byte[] bytesy = msy.ToArray();

MessageBox.Show("Deserialize bytes Length(still intact): " 
   + bytesy.Length.ToString());

Ответ 5

Вам нужно учитывать кодировку, потому что 1 символ может быть представлен 1 или более байтами (до 6), а разные кодировки будут обрабатывать эти байты по-разному.

У Джоэля есть проводка по этому поводу:

Абсолютный минимум Каждый разработчик программного обеспечения Абсолютно, положительно должен знать о Unicode и наборах символов (нет оправданий!)

Ответ 6

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

Общая потребность

Каждая строка имеет набор символов и кодировку. Когда вы конвертируете объект System.String в массив System.Byte, у вас все еще есть набор символов и кодировка. Для большинства случаев использования вы должны знать, какой набор символов и кодировка вам нужен, и .NET упрощает "копирование с преобразованием". Просто выберите подходящий класс Encoding.

// using System.Text;
Encoding.UTF8.GetBytes(".NET String to byte array")

Для преобразования, возможно, потребуется обработать случаи, когда целевой набор символов или кодировка не поддерживают символ, который находится в источнике. У вас есть выбор: исключение, замещение или пропуски. Политика по умолчанию заключается в замене "?".

// using System.Text;
var text = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes("You win €100")); 
                                                      // -> "You win ?100"

Очевидно, что преобразования не обязательно без потерь!

Примечание. Для System.String исходный набор символов - Unicode.

Единственное непонятное, что .NET использует имя набора символов для имени одной конкретной кодировки этого набора символов. Encoding.Unicode следует называть Encoding.UTF16.

Что это для большинства обычаев. Если это вам нужно, перестаньте читать здесь. См. Статью статья Джоэл Спольски, если вы не понимаете, что такое кодировка.

Особая потребность

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

Он не хочет конверсии.

Из С# spec:

Обработка символов и строк в С# использует кодировку Unicode. charтип представляет собой кодовый блок UTF-16, а тип строки представляет собой последовательность кодовых блоков UTF-16.

Итак, мы знаем, что если мы попросим нулевое преобразование (т.е. от UTF-16 до UTF-16), мы получим желаемый результат:

Encoding.Unicode.GetBytes(".NET String to byte array")

Но чтобы избежать упоминания кодировок, мы должны сделать это по-другому. Если допустим промежуточный тип данных, для этого есть концептуальный ярлык:

".NET String to byte array".ToCharArray()

Это не дает нам желаемого типа данных, но Ответ Mehrdad показывает, как преобразовать этот массив Char в массив байтов, используя BlockCopy. Однако это копирует строку дважды! И он слишком явно использует кодирующий код: тип данных System.Char.

Единственный способ получить фактические байты, в которых хранится String, - это использовать указатель. Оператор fixed позволяет принимать адрес значений. Из спецификации С#:

[Для] выражения строки типа... инициализатор вычисляет адрес первого символа в строке.

Для этого компилятор пишет код, пропускающий другие части строкового объекта с помощью RuntimeHelpers.OffsetToStringData. Итак, чтобы получить необработанные байты, просто создайте указатель на строку и скопируйте необходимое количество байтов.

// using System.Runtime.InteropServices
unsafe byte[] GetRawBytes(String s)
{
    if (s == null) return null;
    var codeunitCount = s.Length;
    /* We know that String is a sequence of UTF-16 codeunits 
       and such codeunits are 2 bytes */
    var byteCount = codeunitCount * 2; 
    var bytes = new byte[byteCount];
    fixed(void* pRaw = s)
    {
        Marshal.Copy((IntPtr)pRaw, bytes, 0, byteCount);
    }
    return bytes;
}

Как отметил @CodesInChaos, результат зависит от точности машины. Но автор вопроса не заинтересован в этом.

Ответ 7

Просто чтобы продемонстрировать, что звуковой ответ Mehrdrad работает, его подход может даже сохранить непарные суррогатные символы (из которых многие выровнялись против моего ответа, но в которых все одинаково виновны, например, System.Text.Encoding.UTF8.GetBytes, System.Text.Encoding.Unicode.GetBytes, эти методы кодирования не могут сохранять старшие суррогатные символы d800, а просто заменяют старшие суррогатные символы значением fffd):

using System;

class Program
{     
    static void Main(string[] args)
    {
        string t = "爱虫";            
        string s = "Test\ud800Test"; 

        byte[] dumpToBytes = GetBytes(s);
        string getItBack = GetString(dumpToBytes);

        foreach (char item in getItBack)
        {
            Console.WriteLine("{0} {1}", item, ((ushort)item).ToString("x"));
        }    
    }

    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;
    }

    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);
    }        
}

Выход:

T 54
e 65
s 73
t 74
? d800
T 54
e 65
s 73
t 74

Попробуйте это с System.Text.Encoding.UTF8.GetBytes или System.Text.Encoding.Unicode.GetBytes, они просто заменят старшие суррогатные символы значением fffd

Каждый раз, когда в этом вопросе возникает движение, я все еще думаю о сериализаторе (будь то от Microsoft или от стороннего компонента), который может сохранять строки, даже если он содержит непарные суррогатные символы; Я гуглю это время от времени: сериализация непарного суррогатного персонажа .NET. Это не заставляет меня терять сон, но это немного раздражает, когда время от времени кто-то комментирует мой ответ, что он ошибочен, но их ответы одинаково несовершенны, когда речь идет о непарных суррогатных персонажах.

Черт, Microsoft должна была просто использовать System.Buffer.BlockCopy в своем BinaryFormatter

谢谢!

Ответ 8

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

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

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

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

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

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

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

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

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

Ответ 9

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

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

Ответ 10

Ну, я прочитал все ответы, и они были об использовании кодировки или о сериализации, которая отбрасывает непарные суррогаты.

Плохо, когда строка, например, исходит от SQL Server, где она была построена из байтового массива, хранящего, например, хеш пароля. Если мы отбросим что-либо из него, он сохранит недопустимый хеш, а если мы хотим сохранить его в XML, мы хотим оставить его нетронутым (поскольку средство записи XML отбрасывает исключение для любого найденного непарного суррогата).

Поэтому в таких случаях я использую кодирование байтовых массивов Base64, но, эй, в Интернете есть только одно решение этой проблемы в С#, и в нем есть ошибка, и это только один способ, поэтому я исправил ошибку и переписал процедура. Вот вы, будущие гуглеры:

public static byte[] StringToBytes(string str)
{
    byte[] data = new byte[str.Length * 2];
    for (int i = 0; i < str.Length; ++i)
    {
        char ch = str[i];
        data[i * 2] = (byte)(ch & 0xFF);
        data[i * 2 + 1] = (byte)((ch & 0xFF00) >> 8);
    }

    return data;
}

public static string StringFromBytes(byte[] arr)
{
    char[] ch = new char[arr.Length / 2];
    for (int i = 0; i < ch.Length; ++i)
    {
        ch[i] = (char)((int)arr[i * 2] + (((int)arr[i * 2 + 1]) << 8));
    }
    return new String(ch);
}

Ответ 11

Также объясните, почему кодирование следует принимать во внимание. Не могу ли я просто получить, в каких байтах хранится строка? Почему эта зависимость от кодировки?!!!

Потому что нет такой вещи, как "байты строки".

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

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

Итак, короче говоря, попытка "получить байты строки без использования кодировок" столь же невозможна, как "запись текста без использования какого-либо языка".

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

Ответ 12

С# для преобразования массива string в byte:

public static byte[] StrToByteArray(string str)
{
   System.Text.UTF8Encoding  encoding=new System.Text.UTF8Encoding();
   return encoding.GetBytes(str);
}

Ответ 13

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

string s = "Hello World";

// String to Byte[]

byte[] byte1 = System.Text.Encoding.Default.GetBytes(s);

// OR

byte[] byte2 = System.Text.ASCIIEncoding.Default.GetBytes(s);

// Byte[] to string

string str = System.Text.Encoding.UTF8.GetString(byte1);

Ответ 14

byte[] strToByteArray(string str)
{
    System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
    return enc.GetBytes(str);
}

Ответ 15

Я не уверен, но я думаю, что строка сохраняет свою информацию как массив Chars, который неэффективен с байтами. В частности, определение Char означает "Представляет символ Unicode".

возьмите этот пример:

String str = "asdf éß";
String str2 = "asdf gh";
EncodingInfo[] info =  Encoding.GetEncodings();
foreach (EncodingInfo enc in info)
{
    System.Console.WriteLine(enc.Name + " - " 
      + enc.GetEncoding().GetByteCount(str)
      + enc.GetEncoding().GetByteCount(str2));
}

Обратите внимание, что ответ Unicode равен 14 байтам в обоих случаях, тогда как ответ UTF-8 составляет только 9 байтов для первого и только 7 для второго.

Итак, если вы просто хотите использовать байты, используемые строкой, просто используйте Encoding.Unicode, но это будет неэффективно с объемом памяти.

Ответ 16

С появлением Span<T> выпущенного в С# 7.2, канонический метод захвата основного представления памяти в строке в массив управляемых байтов:

byte[] bytes = "rubbish_\u9999_string".AsSpan().AsBytes().ToArray();

Преобразование обратно должно быть непростым, потому что это означает, что вы на самом деле интерпретируете данные как-то, но ради полноты:

string s;
unsafe
{
    fixed (char* f = &bytes.AsSpan().NonPortableCast<byte, char>().DangerousGetPinnableReference())
    {
        s = new string(f);
    }
}

Имена NonPortableCast и DangerousGetPinnableReference должны NonPortableCast аргумент, что вы, вероятно, не должны этого делать.

Обратите внимание, что для работы с Span<T> требуется установить пакет System.Memory NuGet.

Несмотря на это, фактический исходный вопрос и последующие комментарии подразумевают, что базовая память не "интерпретируется" (что, как я полагаю, означает, что она не изменена и не считана за исключением необходимости записывать ее как есть), что указывает на некоторую реализацию Stream класс должен использоваться вместо рассуждения о данных как о строках вообще.

Ответ 17

Ключевой проблемой является то, что глиф в строке принимает 32 бита (16 бит для символьного кода), но у байта всего 8 бит. Индивидуальное сопоставление не существует, если вы не ограничиваете себя строками, которые содержат только символы ASCII. System.Text.Encoding имеет множество способов сопоставления строки с байтом [], вам нужно выбрать ту, которая позволяет избежать потери информации, и которая проста в использовании вашим клиентом, когда ей нужно сопоставить байт [] назад к строке.

Utf8 - популярная кодировка, компактная и не потеряющая.

Ответ 18

Самый быстрый способ

public static byte[] GetBytes(string text)
{
    return System.Text.ASCIIEncoding.UTF8.GetBytes(text);
}

ИЗМЕНИТЬ как прокомментировал Макотосан, теперь это лучший способ:

Encoding.UTF8.GetBytes(text)

Ответ 19

Использование:

    string text = "string";
    byte[] array = System.Text.Encoding.UTF8.GetBytes(text);

Результат:

[0] = 115
[1] = 116
[2] = 114
[3] = 105
[4] = 110
[5] = 103

Ответ 20

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

Строка в .NET представляет текст как последовательность кодовых единиц UTF-16, поэтому байты кодируются в памяти уже в UTF-16.

Mehrdad Ответ

Вы можете использовать ответ Mehrdad, но на самом деле он использует кодировку, потому что символы UTF-16. Он вызывает ToCharArray, который, глядя на источник, создает char[] и напрямую копирует в него память. Затем он копирует данные в байтовый массив, который также выделяется. Таким образом, он скрывает два байта и выделяет массив символов, который не используется после вызова.

Том Блоджетт Ответ

Ответ Tom Blodget на 20-30% быстрее, чем Mehrdad, поскольку он пропускает промежуточный этап выделения массива char и копирования в него байтов, но требует компиляции с параметром /unsafe. Если вы абсолютно не хотите использовать кодирование, я думаю, что это путь. Если вы поместите свой логин шифрования в fixed блок, вам даже не нужно выделять отдельный массив байтов и копировать в него байты.

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

Потому что это правильный способ сделать это. string - это абстракция.

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

Если вы используете System.Text.Encoding.Unicode, ваш код будет более устойчивым. Вам не нужно беспокоиться о порядке работы системы, в которой будет выполняться ваш код. Вам не нужно беспокоиться, если в следующей версии CLR будет использоваться другая внутренняя кодировка символов.

Я думаю, вопрос не в том, почему вы хотите беспокоиться о кодировке, а в том, почему вы хотите игнорировать ее и использовать что-то еще. Кодирование предназначено для представления абстракции строки в последовательности байтов. System.Text.Encoding.Unicode предоставит вам немного порядковый порядок кодирования байтов и будет выполнять то же самое в каждой системе, сейчас и в будущем.

Ответ 21

Вы можете использовать следующий код для преобразования string в byte array в .NET

string s_unicode = "abcéabc";
byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(s_unicode);

Ответ 22

Ближайшим подходом к вопросу OP является Tom Blodget, который фактически входит в объект и извлекает байты. Я говорю ближе, потому что это зависит от реализации объекта String.

"Can't I simply get what bytes the string has been stored in?"

Конечно, но там, где возникает фундаментальная ошибка в вопросе. Строка - это объект, который может иметь интересную структуру данных. Мы уже знаем, что это происходит, потому что это позволяет хранить непарных суррогатов. Он может хранить длину. Он может содержать указатель на каждый из "парных" суррогатов, позволяющий быстро подсчитывать. И т.д. Все эти дополнительные байты не являются частью символьных данных.

То, что вы хотите, это каждый символ байтов в массиве. И именно здесь происходит "кодирование". По умолчанию вы получите UTF-16LE. Если вы сами не заботитесь о самих байтах, за исключением поездки туда и обратно, вы можете выбрать любую кодировку, включая "по умолчанию", и преобразовать ее позже (при условии, что те же параметры, что и кодировка по умолчанию, кодовые точки, исправления ошибок, разрешенные вещи, такие как непарные суррогаты и т.д.

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

"Why is there a dependency on character encodings?"

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

Это означает, что сохранение строки не имеет значения. Вы хотите, чтобы строка "закодирована" в байты в массиве байтов.

Мне нравится ответ Tom Bloget, потому что он взял вас к направлению "байтов строкового объекта". Это зависит от реализации, и, поскольку он заглядывает внутрь, может быть трудно восстановить копию строки.

Ответ Mehrdad неверен, поскольку он вводит в заблуждение на концептуальном уровне. У вас все еще есть список байтов, закодированных. Его особое решение позволяет сохранить непарные суррогаты - это зависит от реализации. Его конкретное решение не создавало бы строковых байтов точно, если GetBytes по умолчанию возвратил строку в UTF-8.


Я изменил свое мнение об этом (решение Mehrdad) - это не получает байты строки; скорее, он получает байты массива символов, которые были созданы из строки. Независимо от кодирования, тип данных char в С# является фиксированным размером. Это позволяет создать массив байтов с последовательной длиной, и он позволяет воспроизводить массив символов на основе размера массива байтов. Поэтому, если кодировка была UTF-8, но каждый char составлял 6 байтов для размещения наибольшего значения utf8, он все равно работал бы. Так что действительно - кодирование персонажа не имеет значения.

Но использовалось преобразование - каждый символ помещался в поле фиксированного размера (тип символа С#). Однако какое это представление не имеет значения, что технически является ответом на ОП. Итак - если вы все равно собираетесь конвертировать... Почему бы не "закодировать"?

Ответ 23

Вот моя небезопасная реализация преобразования String в Byte[]:

public static unsafe Byte[] GetBytes(String s)
{
    Int32 length = s.Length * sizeof(Char);
    Byte[] bytes = new Byte[length];

    fixed (Char* pInput = s)
    fixed (Byte* pBytes = bytes)
    {
        Byte* source = (Byte*)pInput;
        Byte* destination = pBytes;

        if (length >= 16)
        {
            do
            {
                *((Int64*)destination) = *((Int64*)source);
                *((Int64*)(destination + 8)) = *((Int64*)(source + 8));

                source += 16;
                destination += 16;
            }
            while ((length -= 16) >= 16);
        }

        if (length > 0)
        {
            if ((length & 8) != 0)
            {
                *((Int64*)destination) = *((Int64*)source);

                source += 8;
                destination += 8;
            }

            if ((length & 4) != 0)
            {
                *((Int32*)destination) = *((Int32*)source);

                source += 4;
                destination += 4;
            }

            if ((length & 2) != 0)
            {
                *((Int16*)destination) = *((Int16*)source);

                source += 2;
                destination += 2;
            }

            if ((length & 1) != 0)
            {
                ++source;
                ++destination;

                destination[0] = source[0];
            }
        }
    }

    return bytes;
}

Это намного быстрее, чем принятый anwser, даже если он не такой элегантный, как есть. Вот мои тесты секундомера более 10000000 итераций:

[Second String: Length 20]
Buffer.BlockCopy: 746ms
Unsafe: 557ms

[Second String: Length 50]
Buffer.BlockCopy: 861ms
Unsafe: 753ms

[Third String: Length 100]
Buffer.BlockCopy: 1250ms
Unsafe: 1063ms

Чтобы использовать его, вы должны отметить "Разрешить небезопасный код" в своих свойствах построения проекта. В соответствии с .NET Framework 3.5 этот метод также можно использовать как расширение строки:

public static unsafe class StringExtensions
{
    public static Byte[] ToByteArray(this String s)
    {
        // Method Code
    }
}

Ответ 24

Если вам действительно нужна копия базовых байтов строки, вы можете использовать такую ​​функцию, как следующая. Однако вы не должны читать, чтобы узнать, почему.

[DllImport(
        "msvcrt.dll",
        EntryPoint = "memcpy",
        CallingConvention = CallingConvention.Cdecl,
        SetLastError = false)]
private static extern unsafe void* UnsafeMemoryCopy(
    void* destination,
    void* source,
    uint count);

public static byte[] GetUnderlyingBytes(string source)
{
    var length = source.Length * sizeof(char);
    var result = new byte[length];
    unsafe
    {
        fixed (char* firstSourceChar = source)
        fixed (byte* firstDestination = result)
        {
            var firstSource = (byte*)firstSourceChar;
            UnsafeMemoryCopy(
                firstDestination,
                firstSource,
                (uint)length);
        }
    }

    return result;
}

Эта функция быстро доставит вам копию байтов, лежащих в основе вашей строки. Вы получите эти байты любым способом, который они кодируют в вашей системе. Эта кодировка почти наверняка является UTF-16LE, но это деталь реализации, которую вам не нужно заботиться.

Чтобы просто позвонить, безопаснее, проще и надежнее,

System.Text.Encoding.Unicode.GetBytes()

По всей вероятности, это даст тот же результат, проще набрать, и байты всегда будут округлены с вызовом

System.Text.Encoding.Unicode.GetString()

Ответ 25

Просто используйте это:

byte[] myByte= System.Text.ASCIIEncoding.Default.GetBytes(myString);

Ответ 26

Два способа:

public static byte[] StrToByteArray(this string s)
{
    List<byte> value = new List<byte>();
    foreach (char c in s.ToCharArray())
        value.Add(c.ToByte());
    return value.ToArray();
}

и

public static byte[] StrToByteArray(this string s)
{
    s = s.Replace(" ", string.Empty);
    byte[] buffer = new byte[s.Length / 2];
    for (int i = 0; i < s.Length; i += 2)
        buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16);
    return buffer;
}

Я предпочитаю использовать нижнюю часть чаще, чем верхнюю, не сравнивая их по скорости.

Ответ 27

bytes[] buffer = UnicodeEncoding.UTF8.GetBytes(string something); //for converting to UTF then get its bytes

bytes[] buffer = ASCIIEncoding.ASCII.GetBytes(string something); //for converting to ascii then get its bytes

Ответ 28

простой код с LINQ

string s = "abc"
byte[] b = s.Select(e => (byte)e).ToArray();

EDIT: как указано ниже, это не очень хорошо.

но вы все равно можете использовать его для понимания LINQ с более подходящим кодированием:

string s = "abc"
byte[] b = s.Cast<byte>().ToArray();

Ответ 29

Строка может быть преобразована в массив байтов несколькими способами, из-за следующего факта:.NET поддерживает Unicode, а Unicode стандартизирует несколько разностных кодировок, называемых UTF. Они имеют различную длину байтового представления, но эквивалентны в этом смысле, что при кодировании строки он может быть закодирован обратно в строку, но если строка кодируется одним UTF и декодируется в предположении о разном UTF, если его можно навинтить вверх.

Кроме того,.NET поддерживает кодировки, отличные от Unicode, но они недействительны в общем случае (будут действительны только в том случае, если ограниченный подмножество кодовой точки Unicode используется в реальной строке, такой как ASCII). Внутренне .NET поддерживает UTF-16, но для представления потока обычно используется UTF-8. Это также стандартно-де-факто для Интернета.

Неудивительно, что сериализация строки в массив байтов и десериализация поддерживается классом System.Text.Encoding, который является абстрактным классом; его производные классы поддерживают конкретные кодировки: ASCIIEncoding и четыре UTF (System.Text.UnicodeEncoding поддерживает UTF-16)

Ref эта ссылка.

Для сериализации массива байтов с помощью System.Text.Encoding.GetBytes. Для обратной операции используйте System.Text.Encoding.GetChars. Эта функция возвращает массив символов, поэтому для получения строки используйте конструктор строк System.String(char[]).
Ссылка на эту страницу.

Пример:

string myString = //... some string

System.Text.Encoding encoding = System.Text.Encoding.UTF8; //or some other, but prefer some UTF is Unicode is used
byte[] bytes = encoding.GetBytes(myString);

//next lines are written in response to a follow-up questions:

myString = new string(encoding.GetChars(bytes));
byte[] bytes = encoding.GetBytes(myString);
myString = new string(encoding.GetChars(bytes));
byte[] bytes = encoding.GetBytes(myString);

//how many times shall I repeat it to show there is a round-trip? :-)

Ответ 30

Это зависит от того, что вы хотите байтов FOR

Это потому, что, поскольку Тайлер так метко сказал, "Строки не являются чистыми данными, у них также есть information." В этом случае информация представляет собой кодировку, которая была принята при создании строки.

Предполагая, что у вас есть двоичные данные (а не текст), хранящиеся в строке

Это основано на комментариях OP по его собственному вопросу, и это правильный вопрос, если я понимаю подсказки OP в прецеденте.

Сохранение двоичных данных в строках, вероятно, является неправильным подходом из-за предполагаемого кодирования, упомянутого выше! Независимо от того, какая программа или библиотека хранит эти двоичные данные в string (вместо массива byte[], который был бы более уместным), он уже проиграл битву до ее начала. Если они отправляют вам байты в запросе/ответе REST или что-либо, что должно передавать строки, Base64 будет правильным подходом.

Если у вас есть текстовая строка с неизвестной кодировкой

Все остальные неверно ответили на этот неправильный вопрос.

Если строка выглядит хорошо как-есть, просто выберите кодировку (желательно, начиная с UTF), используйте соответствующую функцию System.Text.Encoding.???.GetBytes() и сообщите, кто бы вы ни отправили байты, в которые вы выбрали кодировку.