utf8 Como faço para obter uma representação de byte consistente de seqüências de caracteres em c#sem especificar manualmente uma codificação?




unicode character c# (24)

A resposta aceita é muito, muito complicada. Use as classes .NET incluídas para isso:

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

Não reinvente a roda se você não precisa ...

Como converter uma string para um byte[] no .NET (C #) sem especificar manualmente uma codificação específica?

Eu vou criptografar a string. Eu posso criptografá-lo sem converter, mas ainda gostaria de saber por que a codificação vem aqui.

Além disso, por que a codificação deve ser levada em consideração? Não consigo simplesmente saber em que bytes a string foi armazenada? Por que há uma dependência nas codificações de caracteres?


Bem, eu li todas as respostas e elas estavam sobre o uso de codificação ou sobre a serialização que substitui substitutos não pareados.

É ruim quando a string, por exemplo, vem do SQL Server, onde foi construída a partir de um array de bytes que armazena, por exemplo, um hash de senha. Se descartarmos alguma coisa dele, ele armazenará um hash inválido e, se quisermos armazená-lo em XML, queremos deixá-lo intacto (porque o gravador XML descarta uma exceção em qualquer substituto não-pareado encontrado).

Então, eu uso a codificação Base64 de matrizes de bytes em tais casos, mas ei, na Internet existe apenas uma solução para isso em C #, e ele tem bug nele e é apenas uma maneira, então eu consertei o bug e gravei de volta procedimento. Aqui estão vocês, futuros googlers:

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

Esta é uma pergunta popular. É importante entender o que o autor da pergunta está fazendo e que é diferente da provável necessidade mais comum. Para desencorajar o uso indevido do código onde ele não é necessário, respondi o primeiro primeiro.

Necessidade Comum

Cada string possui um conjunto de caracteres e codificação. Quando você converte um objeto System.String em uma matriz de System.Byte você ainda tem um conjunto de caracteres e codificação. Para a maioria dos usos, você saberá qual conjunto de caracteres e codificação você precisa e o .NET simplifica a "cópia com conversão". Basta escolher a classe de Encoding apropriada.

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

A conversão pode precisar lidar com casos em que o conjunto de caracteres de destino ou a codificação não suporta um caractere que esteja na origem. Você tem algumas opções: exceção, substituição ou pular. A política padrão é substituir um '?'.

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

Claramente, as conversões não são necessariamente sem perdas!

Nota: Para System.String o conjunto de caracteres de origem é Unicode.

A única coisa confusa é que o .NET usa o nome de um conjunto de caracteres para o nome de uma codificação específica desse conjunto de caracteres. Encoding.Unicode deve ser chamado de Encoding.UTF16 .

É isso para a maioria dos usos. Se é isso que você precisa, pare de ler aqui. Veja o divertido joelonsoftware.com/articles/Unicode.html se você não entender o que é uma codificação.

Necessidade Específica

Agora, o autor da pergunta pergunta: "Cada string é armazenada como uma matriz de bytes, certo? Por que não posso simplesmente ter esses bytes?"

Ele não quer nenhuma conversão.

Da especificação C # :

Caractere e processamento de seqüência de caracteres em C # usa codificação Unicode. O tipo char representa uma unidade de código UTF-16 e o ​​tipo string representa uma sequência de unidades de código UTF-16.

Então, sabemos que, se pedirmos a conversão nula (isto é, de UTF-16 para UTF-16), obteremos o resultado desejado:

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

Mas, para evitar a menção de codificações, devemos fazer isso de outra maneira. Se um tipo de dados intermediário for aceitável, há um atalho conceitual para isso:

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

Isso não nos dá o tipo de dados desejado, mas a resposta de Mehrdad mostra como converter essa matriz Char em uma matriz Byte usando BlockCopy . No entanto, isso copia a seqüência de caracteres duas vezes! E, também, explicitamente, usa código específico de codificação: o tipo de dados System.Char .

A única maneira de obter os bytes reais em que a String está armazenada é usar um ponteiro. A declaração fixed permite pegar o endereço dos valores. Da especificação C #:

[Para] uma expressão do tipo string, ... o inicializador calcula o endereço do primeiro caractere na string.

Para fazer isso, o compilador escreve o código ignorando as outras partes do objeto string com RuntimeHelpers.OffsetToStringData . Então, para obter os bytes brutos, basta criar um ponteiro para a string e copiar o número de bytes necessários.

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

Como apontaram @CodesInChaos, o resultado depende do endianness da máquina. Mas o autor da pergunta não está preocupado com isso.


Também explique por que a codificação deve ser levada em consideração. Não consigo simplesmente saber em que bytes a string foi armazenada? Por que essa dependência na codificação? !!!

Porque não existe tal coisa como "os bytes da string".

Uma string (ou mais genericamente, um texto) é composta de caracteres: letras, dígitos e outros símbolos. Isso é tudo. Computadores, no entanto, não sabem nada sobre personagens; eles só podem manipular bytes. Portanto, se você deseja armazenar ou transmitir texto usando um computador, é necessário transformar os caracteres em bytes. Como você faz isso? Aqui é onde as codificações vêm para a cena.

Uma codificação não é nada além de uma convenção para converter caracteres lógicos em bytes físicos. A codificação mais simples e mais conhecida é ASCII, e é tudo que você precisa se escrever em inglês. Para outros idiomas, você precisará de codificações mais completas, sendo que qualquer um dos sabores Unicode é a escolha mais segura hoje em dia.

Então, em suma, tentar "obter os bytes de uma string sem usar codificações" é tão impossível quanto "escrever um texto sem usar nenhuma linguagem".

A propósito, eu recomendo fortemente que você (e qualquer um, por falar nisso) leia este pequeno pedaço de sabedoria: joelonsoftware.com/articles/Unicode.html


Como converter uma string para um byte [] no .NET (C #) sem especificar manualmente uma codificação específica?

Uma string no .NET representa o texto como uma seqüência de unidades de código UTF-16, portanto, os bytes já estão codificados na memória em UTF-16.

Resposta do Mehrdad

Você pode usar a resposta do Mehrdad , mas na verdade usa uma codificação porque os caracteres são UTF-16. Ele chama ToCharArray que, olhando para a fonte, cria um char[]e copia a memória diretamente para ele. Em seguida, copia os dados para uma matriz de bytes que também está alocada. Então, sob o capô, ele está copiando os bytes subjacentes duas vezes e alocando uma matriz char que não é usada após a chamada.

Resposta de Tom Blodget

A resposta do Tom Blodget é 20-30% mais rápida do que o Mehrdad, já que ele pula a etapa intermediária de alocar uma matriz char e copiar os bytes para ela, mas requer que você compile com a /unsafeopção. Se você absolutamente não quer usar a codificação, acho que este é o caminho a percorrer. Se você colocar seu login de criptografia dentro do fixedbloco, você nem precisa alocar uma matriz de bytes separada e copiar os bytes para ela.

Além disso, por que a codificação deve ser levada em consideração? Não consigo simplesmente saber em que bytes a string foi armazenada? Por que há uma dependência nas codificações de caracteres?

Porque essa é a maneira correta de fazer isso. stringé uma abstração.

Usar uma codificação pode lhe causar problemas se você tiver 'strings' com caracteres inválidos, mas isso não deve acontecer. Se você está recebendo dados em sua string com caracteres inválidos, está fazendo errado. Você provavelmente deveria estar usando uma matriz de bytes ou uma codificação Base64 para começar.

Se você usar System.Text.Encoding.Unicode, seu código será mais resiliente. Você não precisa se preocupar com o endianness do sistema em que seu código será executado. Você não precisa se preocupar se a próxima versão do CLR usar uma codificação de caracteres interna diferente.

Eu acho que a questão não é por que você quer se preocupar com a codificação, mas porque você quer ignorá-la e usar outra coisa. Codificação destina-se a representar a abstração de uma seqüência de caracteres em uma seqüência de bytes. System.Text.Encoding.Unicodelhe dará uma pequena codificação de ordem de byte endian e executará o mesmo em todos os sistemas, agora e no futuro.


A questão-chave é que um glifo em uma string leva 32 bits (16 bits para um código de caractere), mas um byte tem apenas 8 bits de sobra. Um mapeamento um-para-um não existe, a menos que você se restrinja a cadeias de caracteres que contenham caracteres ASCII. System.Text.Encoding tem muitas maneiras de mapear uma string para byte [], você precisa escolher uma que evite a perda de informação e que seja fácil de usar pelo seu cliente quando ela precisar mapear o byte [] de volta para uma string. .

Utf8 é uma codificação popular, é compacta e não com perdas.


Apenas para demonstrar que a share sonora de Mehrdrad funciona, sua abordagem pode até mesmo persistir nos [BinaryFormatter (dos quais muitos se nivelaram contra minha resposta, mas dos quais todos são igualmente culpados, por exemplo, System.Text.Encoding.UTF8.GetBytes , System.Text.Encoding.Unicode.GetBytes ; esses métodos de codificação não podem persistir os altos caracteres substitutos d800 por exemplo, e aqueles apenas substituem os caracteres substitutos altos pelo valor 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);
    }        
}

Saída:

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

Tente isso com System.Text.Encoding.UTF8.GetBytes ou System.Text.Encoding.Unicode.GetBytes , eles apenas substituirão caracteres substitutos altos pelo valor fffd

Toda vez que há um movimento nessa questão, ainda estou pensando em um serializador (seja da Microsoft ou de um componente de terceiros) que pode persistir cadeias, mesmo que contenha caracteres substitutos não-pareados; Eu google isso de vez em quando: serialização caráter substituto não emparelhado . Isso não me faz perder o sono, mas é meio chato quando, de vez em quando, alguém comentando a minha resposta é falho, mas as respostas são igualmente falhas quando se trata de personagens substitutos não pareados.

Darn, Microsoft deveria ter usado apenas System.Buffer.BlockCopy no seu BinaryFormatter

谢谢!


Se você realmente quiser uma cópia dos bytes subjacentes de uma string, você pode usar uma função como a que segue. No entanto, você não deve, por favor, ler para descobrir o porquê.

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

Esta função irá obter uma cópia dos bytes subjacentes à sua string, muito rapidamente. Você obterá esses bytes da maneira que eles estão codificando no seu sistema. Essa codificação é quase certamente UTF-16LE, mas esse é um detalhe de implementação com o qual você não deveria se preocupar.

Seria mais seguro, mais simples e mais confiável ligar,

System.Text.Encoding.Unicode.GetBytes()

Com toda a probabilidade, isso dará o mesmo resultado, será mais fácil de digitar e os bytes sempre farão uma viagem de ida e volta

System.Text.Encoding.Unicode.GetString()

Simplesmente use isto:

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

Maneira mais rápida

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

EDIT como Makotosan comentou que esta é agora a melhor maneira:

Encoding.UTF8.GetBytes(text)

Não tenho certeza, mas acho que a string armazena suas informações como uma matriz de Chars, que é ineficiente com bytes. Especificamente, a definição de um Char é "Representa um caractere Unicode".

pegue este exemplo exemplo:

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

Tome nota que a resposta Unicode é 14 bytes em ambas as instâncias, enquanto a resposta UTF-8 é de apenas 9 bytes para o primeiro e apenas 7 para o segundo.

Então, se você quer apenas os bytes usados ​​pela string, simplesmente use Encoding.Unicode, mas será ineficiente com o espaço de armazenamento.


Tente isso, muito menos código:

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

A abordagem mais próxima da pergunta do OP é a de Tom Blodget, que realmente entra no objeto e extrai os bytes. Eu digo mais perto porque depende da implementação do objeto String.

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

Claro, mas é aí que o erro fundamental na questão surge. O String é um objeto que poderia ter uma estrutura de dados interessante. Nós já sabemos, porque permite que substitutos não-pareados sejam armazenados. Pode armazenar o comprimento. Pode manter um ponteiro para cada um dos substitutos 'emparelhados' permitindo a contagem rápida. Etc. Todos esses bytes extras não fazem parte dos dados do caractere.

O que você quer é os bytes de cada caractere em uma matriz. E é aí que entra a 'codificação'. Por padrão, você obterá o UTF-16LE. Se você não se importa com os bytes, exceto a ida e volta, então você pode escolher qualquer codificação incluindo o 'padrão', e convertê-lo de volta mais tarde (assumindo os mesmos parâmetros como codificação padrão, pontos de código, correções de bugs , coisas permitidas como substitutos não pareados, etc.

Mas por que deixar a "codificação" até mágica? Por que não especificar a codificação para que você saiba quais bytes você obterá?

"Why is there a dependency on character encodings?"

Codificação (neste contexto) significa simplesmente os bytes que representam sua string. Não os bytes do objeto string. Você queria os bytes em que a string foi armazenada - é aqui que a pergunta foi feita ingenuamente. Você queria os bytes de string em uma matriz contígua que representa a string, e não todos os outros dados binários que um objeto de string pode conter.

O que significa que uma string é armazenada é irrelevante. Você deseja uma seqüência "codificada" em bytes em uma matriz de bytes.

Eu gosto da resposta do Tom Bloget porque ele levou você para a direção 'bytes da string'. Entretanto, a implementação é dependente e, como ele está espiando internamente, pode ser difícil reconstituir uma cópia da string.

A resposta de Mehrdad está errada porque é enganosa no nível conceitual. Você ainda tem uma lista de bytes, codificados. Sua solução particular permite que substitutos desemparelhados sejam preservados - isso depende da implementação. Sua solução particular não produziria os bytes da string com precisão se GetBytesretornasse a string em UTF-8 por padrão.

Eu mudei de idéia sobre isso (a solução de Mehrdad) - isso não está recebendo os bytes da string; em vez disso, está obtendo os bytes da matriz de caracteres que foi criada a partir da string. Independentemente da codificação, o tipo de dados char em c # é um tamanho fixo. Isso permite que uma matriz de bytes de comprimento consistente seja produzida e permite que a matriz de caracteres seja reproduzida com base no tamanho da matriz de bytes. Portanto, se a codificação fosse UTF-8, mas cada caractere tivesse 6 bytes para acomodar o maior valor utf8, ainda assim funcionaria. Então, de fato - a codificação do personagem não importa.

Mas uma conversão foi usada - cada caractere foi colocado em uma caixa de tamanho fixo (tipo de caractere c #). No entanto, o que é essa representação não importa, o que é tecnicamente a resposta ao OP. Então - se você for converter mesmo assim ... Por que não 'codificar'?


A cadeia de caracteres pode ser convertida em matriz de bytes de diversas maneiras, devido ao seguinte fato: O .NET oferece suporte a Unicode e o Unicode padroniza várias codificações de diferenças chamadas UTFs. Eles têm diferentes comprimentos de representação de byte, mas são equivalentes no sentido de que quando uma string é codificada, ela pode ser codificada de volta para a string, mas se a string for codificada com uma UTF e decodificada na suposição de UTF diferente se puder ser parafusada acima.

Além disso, o .NET suporta codificações não Unicode, mas elas não são válidas no caso geral (serão válidas somente se um subconjunto limitado de pontos de código Unicode for usado em uma cadeia real, como ASCII). Internamente, o .NET suporta UTF-16, mas para a representação de fluxo, o UTF-8 é geralmente usado. Também é um padrão de fato para a Internet.

Não surpreendentemente, a serialização da cadeia em uma matriz de byte e desserialização é suportada pela classe System.Text.Encoding, que é uma classe abstrata; suas classes derivadas suportam codificações concretas: ASCIIEncodinge quatro UTFs ( System.Text.UnicodeEncodingsuportam UTF-16)

Refira este link.

Para serialização para uma matriz de bytes usando System.Text.Encoding.GetBytes. Para a operação inversa use System.Text.Encoding.GetChars. Esta função retorna uma matriz de caracteres, portanto, para obter uma string, use um construtor de string System.String(char[]).
Refira esta página.

Exemplo:

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

Você pode usar o seguinte código para conversão entre matriz de seqüência de caracteres e byte.

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

Você pode usar o seguinte código para converter um stringem um byte arrayno .net

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

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

Com o advento do Span<T>lançado com o C # 7.2, a técnica canônica para capturar a representação de memória subjacente de uma cadeia em uma matriz de bytes gerenciados é:

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

Convertê-lo de volta deve ser um não-inicial, porque isso significa que você está de fato interpretando os dados de alguma forma, mas por uma questão de completude:

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

Os nomes NonPortableCaste DangerousGetPinnableReferencedevem promover o argumento de que você provavelmente não deveria estar fazendo isso.

Observe que trabalhar com Span<T>requer a instalação do pacote System.Memory NuGet .

Independentemente disso, a real pergunta original e comentários de acompanhamento implica que a memória subjacente não está sendo "interpretado" (que eu suponho meios não é modificado ou ler além da necessidade de escrevê-lo como-é), indicando que alguns implementação da Streamclasse deve ser usado em vez de raciocinar sobre os dados como sequências de caracteres.


Dois caminhos:

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

E,

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

Eu costumo usar o inferior com mais frequência do que o topo, não os comparei por velocidade.


Usar:

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

O resultado é:

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

C # para converter um stringpara um bytearray:

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

Ao contrário das respostas aqui, você NÃO precisa se preocupar com a codificação se os bytes não precisarem ser interpretados!

Como você mencionou, seu objetivo é, simplesmente, "pegar em que bytes a string foi armazenada" .
(E, claro, para poder reconstruir a string a partir dos bytes.)

Para esses objetivos, eu sinceramente não entendo por que as pessoas continuam dizendo que você precisa das codificações. Você certamente não precisa se preocupar com codificações para isso.

Apenas faça isso em vez disso:

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

Enquanto seu programa (ou outros programas) não tentar interpretar os bytes de alguma forma, o que obviamente você não mencionou que pretende fazer, então não há nada de errado com essa abordagem! Preocupar-se com codificações só torna sua vida mais complicada sem nenhuma razão real.

Benefício adicional para esta abordagem:

Não importa se a string contém caracteres inválidos, porque você ainda pode obter os dados e reconstruir a string original de qualquer maneira!

Ele será codificado e decodificado da mesma forma, porque você está apenas olhando para os bytes .

Se você usasse uma codificação específica, no entanto, teria lhe dado problemas com a codificação / decodificação de caracteres inválidos.


A primeira parte da sua pergunta (como obter os bytes) já foi respondida por outras pessoas: procure no namespace System.Text.Encoding .

Vou abordar sua pergunta de acompanhamento: por que você precisa escolher uma codificação? Por que você não consegue isso da própria classe de string?

A resposta está em duas partes.

Primeiro de tudo, os bytes usados ​​internamente pela classe de strings não importam , e sempre que você assume que eles estão provavelmente introduzindo um bug.

Se o seu programa estiver totalmente dentro do mundo do .Net, você não precisa se preocupar em obter matrizes de bytes para cadeias de caracteres, mesmo que esteja enviando dados por uma rede. Em vez disso, use Serialização .Net para se preocupar com a transmissão dos dados. Você não se preocupa mais com os bytes reais: o formatador de serialização faz isso por você.

Por outro lado, e se você estiver enviando esses bytes para algum lugar que não possa garantir que os dados sejam extraídos de um fluxo serializado em .Net? Neste caso você definitivamente precisa se preocupar com a codificação, porque obviamente este sistema externo se importa. Então, novamente, os bytes internos usados ​​pela string não importam: você precisa escolher uma codificação para poder ser explícito sobre essa codificação no final do recebimento, mesmo que seja a mesma codificação usada internamente pelo .Net.

Eu entendo que, neste caso, você pode preferir usar os bytes reais armazenados pela variável de seqüência de caracteres na memória, sempre que possível, com a ideia de que pode economizar algum trabalho criando seu fluxo de bytes. No entanto, eu coloquei para você, não é importante, em comparação com a certeza de que sua saída é entendida do outro lado, e para garantir que você deve ser explícito com sua codificação. Além disso, se você realmente deseja corresponder aos seus bytes internos, basta escolher a codificação Unicode e obter essa economia de desempenho.

O que me leva à segunda parte ... escolhendo a codificação Unicode está dizendo .net para usar os bytes subjacentes. Você precisa escolher essa codificação, porque quando algum novo Unicode-Plus sai, o tempo de execução do .Net precisa estar livre para usar este modelo de codificação melhor e mais novo sem quebrar seu programa. Mas, no momento (e no futuro previsível), apenas a escolha da codificação Unicode fornece o que você deseja.

Também é importante entender que sua string precisa ser reescrita para ser ligada, e isso envolve pelo menos alguma tradução do padrão de bits, mesmo quando você usa uma codificação correspondente . O computador precisa explicar coisas como Big vs Little Endian, ordem de bytes de rede, pacote, informações de sessão, etc.


Aqui está minha implementação insegura Stringda Byte[]conversão:

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

É muito mais rápido do que o do aceito, mesmo que não seja tão elegante quanto é. Aqui estão os meus benchmarks do Cronômetro acima de 10000000 iterações:

[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

Para usá-lo, você precisa marcar "Permitir código não seguro" nas propriedades de criação do seu projeto. De acordo com o .NET Framework 3.5, esse método também pode ser usado como extensão String:

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




character-encoding