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

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

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

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

30 ответов


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

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

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

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

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

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

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

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

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

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


Это зависит от кодировки строки (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 framework использует UTF-16 для представления строк, поэтому, если вы просто хотите получить точные байты, которые использует .NET, используйте System.Text.Encoding.Unicode.GetBytes (...).

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


принятый ответ очень, очень сложный. Используйте включенные классы .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);

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


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

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

у Джоэла есть сообщение об этом:

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


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

Общее

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

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

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

// 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.

это для большинства использований. Если это то, что вам нужно, прекратите читать здесь. читать весело!--33-->статья Джоэла Спольского если вы не понимаете, что такое кодирование есть.

Конкретной

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

он не хочет никакого обращения.

С в C# спецификации:

обработка символов и строк в C# использует кодировку Unicode. Пеструшка тип представляет кодовую единицу UTF-16, а строковый тип представляет последовательность кода UTF-16 единицы.

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

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

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

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

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

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

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

для этого компилятор записывает код, пропуская другие части строкового объекта с помощью 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, результат зависит от endianness машины. Но автора вопроса это не касается.


просто чтобы продемонстрировать, что звук 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("TEST String");

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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, но это будет неэффективно с пространством для хранения.


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

Utf8 является популярным кодировка, она компактна и не потеряна.


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

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

редактировать как прокомментировал Макотосан, теперь это лучший способ:

Encoding.UTF8.GetBytes(text)

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

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

результат:

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

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

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

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

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

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

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

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

"Why is there a dependency on character encodings?"

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

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

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

GetBytes по умолчанию возвращает строку в UTF-8.

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

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


С появлением Span<T> выпущенный с C# 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 следует продолжить аргумент, который вы, вероятно, не должны делать этот.

обратите внимание, что работая с Span<T> требует установки


вот моя небезопасная реализация String to 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
    }
}

два варианта:

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

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


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

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

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

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

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

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

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

[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()

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

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

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

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

ответ Мехрдада

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

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

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

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

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

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

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

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


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

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

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

Ref этой ссылке.

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

пример:

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? :-)

С byte[] to string:

        return BitConverter.ToString(bytes);