Como converter UTF-8 byte [] para string?

932

Eu tenho uma byte[]matriz que é carregada de um arquivo que eu conheço contém UTF-8 .

Em algum código de depuração, preciso convertê-lo em uma string. Existe um liner que fará isso?

Nos bastidores , deve ser apenas uma alocação e uma cópia , portanto, mesmo que não seja implementado, deve ser possível.

BCS
fonte
5
"deve ser apenas uma alocação e uma cópia": não está correta porque uma string .NET está codificada em UTF-16. Um caractere Unicode pode ser uma unidade de código UTF-8 ou uma unidade de código UTF-16. outro pode ser duas unidades de código UTF-8 ou uma unidade de código UTF-16, outro pode ser três unidades de código UTF-8 ou uma unidade de código UTF-16, outro pode ser quatro unidades de código UTF-8 ou duas unidades de código UTF-16 . Um memcopy pode ampliar, mas não pode lidar com a conversão de UTF-8 para UTF-16.
precisa

Respostas:

1470
string result = System.Text.Encoding.UTF8.GetString(byteArray);
Zanoni
fonte
13
como ele lida com seqüências de caracteres nulas?
Maazza
14
@maazza por motivo desconhecido, não existe. Estou chamando assim System.Text.Encoding.UTF8.GetString(buf).TrimEnd('\0');.
27915 Oi-Angel as
15
@ Hi-Angel razão desconhecida? O único motivo pelo qual as seqüências terminadas em nulo se tornaram populares foi a linguagem C - e isso ocorreu apenas por causa de uma estranheza histórica (instruções da CPU que lidavam com as seqüências terminadas em nulo). O .NET usa apenas seqüências terminadas em nulo ao interoptar com código que usa seqüências terminadas em nulo (que finalmente estão desaparecendo). É perfeitamente válido que uma string contenha caracteres NUL. E, é claro, enquanto as seqüências terminadas em nulo são simples no ASCII (apenas crie até você obter o primeiro byte zero), outras codificações, incluindo UTF-8, não são tão simples.
Luaan 23/11
4
Uma das belas características do UTF-8 é que uma sequência mais curta nunca é uma subsequência de uma sequência mais longa. Portanto, uma sequência UTF-8 terminada em nulo é simples.
plugwash
10
Bem, boa sorte em desempacotá-lo se tiver não-ascii. Basta usar Convert.ToBase64String.
Erik Bergstedt
323

Há pelo menos quatro maneiras diferentes de fazer essa conversão.

  1. GetString da codificação
    , mas você não poderá recuperar os bytes originais se esses bytes tiverem caracteres não ASCII.

  2. BitConverter.ToString
    A saída é uma cadeia delimitada por "-", mas não há um método interno do .NET para converter a cadeia em matriz de bytes.

  3. Convert.ToBase64String
    Você pode converter facilmente a sequência de saída de volta em matriz de bytes usando Convert.FromBase64String.
    Nota: A sequência de saída pode conter '+', '/' e '='. Se você deseja usar a cadeia de caracteres em uma URL, é necessário codificá-la explicitamente.

  4. HttpServerUtility.UrlTokenEncode
    Você pode converter facilmente a sequência de saída de volta em matriz de bytes usando HttpServerUtility.UrlTokenDecode. A string de saída já é compatível com URL! A desvantagem é que precisa de System.Webmontagem se o seu projeto não for um projeto da web.

Um exemplo completo:

byte[] bytes = { 130, 200, 234, 23 }; // A byte array contains non-ASCII (or non-readable) characters

string s1 = Encoding.UTF8.GetString(bytes); // ���
byte[] decBytes1 = Encoding.UTF8.GetBytes(s1);  // decBytes1.Length == 10 !!
// decBytes1 not same as bytes
// Using UTF-8 or other Encoding object will get similar results

string s2 = BitConverter.ToString(bytes);   // 82-C8-EA-17
String[] tempAry = s2.Split('-');
byte[] decBytes2 = new byte[tempAry.Length];
for (int i = 0; i < tempAry.Length; i++)
    decBytes2[i] = Convert.ToByte(tempAry[i], 16);
// decBytes2 same as bytes

string s3 = Convert.ToBase64String(bytes);  // gsjqFw==
byte[] decByte3 = Convert.FromBase64String(s3);
// decByte3 same as bytes

string s4 = HttpServerUtility.UrlTokenEncode(bytes);    // gsjqFw2
byte[] decBytes4 = HttpServerUtility.UrlTokenDecode(s4);
// decBytes4 same as bytes
detale
fonte
7
LINQ-lo:var decBytes2 = str.Split('-').Select(ch => Convert.ToByte(ch, 16)).ToArray();
drtf
25

Uma solução geral para converter de matriz de bytes em string quando você não conhece a codificação:

static string BytesToStringConverted(byte[] bytes)
{
    using (var stream = new MemoryStream(bytes))
    {
        using (var streamReader = new StreamReader(stream))
        {
            return streamReader.ReadToEnd();
        }
    }
}
Nir
fonte
3
Mas isso pressupõe que exista uma BOM de codificação no fluxo de bytes ou que esteja no UTF-8. Mas você pode fazer o mesmo com a codificação de qualquer maneira. Não resolve magicamente o problema quando você não conhece a codificação.
Sebastian Zander
12

Definição:

public static string ConvertByteToString(this byte[] source)
{
    return source != null ? System.Text.Encoding.UTF8.GetString(source) : null;
}

Usando:

string result = input.ConvertByteToString();
Erçin Dedeoğlu
fonte
9

Converter um byte[]para um stringparece simples, mas qualquer tipo de codificação provavelmente atrapalha a string de saída. Esta pequena função simplesmente funciona sem resultados inesperados:

private string ToString(byte[] bytes)
{
    string response = string.Empty;

    foreach (byte b in bytes)
        response += (Char)b;

    return response;
}
AndrewJE
fonte
Recebi System.FormatException usando seu método quando eu o descompactei com Convert.FromBase64String.
Erik Bergstedt
@ AndrewJE isso levará um tempo até para calcular se você tiver uma matriz de bytes grande como a usada nas fotos.
user3841581
7

Usando (byte)b.ToString("x2"), Saídasb4b5dfe475e58b67

public static class Ext {

    public static string ToHexString(this byte[] hex)
    {
        if (hex == null) return null;
        if (hex.Length == 0) return string.Empty;

        var s = new StringBuilder();
        foreach (byte b in hex) {
            s.Append(b.ToString("x2"));
        }
        return s.ToString();
    }

    public static byte[] ToHexBytes(this string hex)
    {
        if (hex == null) return null;
        if (hex.Length == 0) return new byte[0];

        int l = hex.Length / 2;
        var b = new byte[l];
        for (int i = 0; i < l; ++i) {
            b[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
        }
        return b;
    }

    public static bool EqualsTo(this byte[] bytes, byte[] bytesToCompare)
    {
        if (bytes == null && bytesToCompare == null) return true; // ?
        if (bytes == null || bytesToCompare == null) return false;
        if (object.ReferenceEquals(bytes, bytesToCompare)) return true;

        if (bytes.Length != bytesToCompare.Length) return false;

        for (int i = 0; i < bytes.Length; ++i) {
            if (bytes[i] != bytesToCompare[i]) return false;
        }
        return true;
    }

}
metadings
fonte
4

Há também a classe UnicodeEncoding, bastante simples de usar:

ByteConverter = new UnicodeEncoding();
string stringDataForEncoding = "My Secret Data!";
byte[] dataEncoded = ByteConverter.GetBytes(stringDataForEncoding);

Console.WriteLine("Data after decoding: {0}", ByteConverter.GetString(dataEncoded));
PK
fonte
Mas não UTF-8 methinks?
David.pfx
1
UnicodeEncodingé o pior nome de classe de todos os tempos; unicode não é uma codificação. Essa classe é realmente UTF-16. A versão little-endian, eu acho.
Nyerguds
3

Alternativamente:

 var byteStr = Convert.ToBase64String(bytes);
Fehr
fonte
2

Um linq de uma linha do Linq para converter uma matriz de bytes byteArrFilenamelida de um arquivo em uma string terminada em zero ASCII pura no estilo C seria esta: Útil para ler coisas como tabelas de índice de arquivos em formatos de arquivo antigos.

String filename = new String(byteArrFilename.TakeWhile(x => x != 0)
                              .Select(x => x < 128 ? (Char)x : '?').ToArray());

Eu uso '?'como char padrão para qualquer coisa não pura ascii aqui, mas isso pode ser alterado, é claro. Se você quiser ter certeza de que pode detectá-lo, basta usar '\0', pois desde TakeWhileo início garante que uma sequência criada dessa maneira não possa conter '\0'valores da fonte de entrada.

Nyerguds
fonte
2

BitConverterA classe pode ser usada para converter um byte[]para string.

var convertedString = BitConverter.ToString(byteAttay);

A documentação da BitConverterclasse pode ser encontrada no MSDN

Sagar
fonte
1
Isso converte a matriz de bytes em uma sequência hexadecimal que representa cada byte, o que geralmente não é o que você deseja ao converter bytes em uma sequência. Se o fizer, essa é outra questão, veja, por exemplo, Como converter a matriz de bytes em seqüência hexadecimal e vice-versa? .
CodeCaster 5/17/17
Não é o que o OP perguntou #
1920
2

Que eu saiba, nenhuma das respostas dadas garante um comportamento correto com terminação nula. Até que alguém me mostre de maneira diferente, escrevi minha própria classe estática para lidar com isso com os seguintes métodos:

// Mimics the functionality of strlen() in c/c++
// Needed because niether StringBuilder or Encoding.*.GetString() handle \0 well
static int StringLength(byte[] buffer, int startIndex = 0)
{
    int strlen = 0;
    while
    (
        (startIndex + strlen + 1) < buffer.Length // Make sure incrementing won't break any bounds
        && buffer[startIndex + strlen] != 0       // The typical null terimation check
    )
    {
        ++strlen;
    }
    return strlen;
}

// This is messy, but I haven't found a built-in way in c# that guarentees null termination
public static string ParseBytes(byte[] buffer, out int strlen, int startIndex = 0)
{
    strlen = StringLength(buffer, startIndex);
    byte[] c_str = new byte[strlen];
    Array.Copy(buffer, startIndex, c_str, 0, strlen);
    return Encoding.UTF8.GetString(c_str);
}

A razão para isso startIndexfoi no exemplo em que eu estava trabalhando especificamente, que eu precisava analisar a byte[]como uma matriz de seqüências terminadas nulas. Pode ser ignorado com segurança no caso simples

Assimilater
fonte
A minha, na verdade. byteArr.TakeWhile(x => x != 0)é uma maneira rápida e fácil de resolver o problema de terminação nula.
Nyerguds
1

hier é um resultado em que você não precisa se preocupar com a codificação. Usei-o na minha classe de rede e envie objetos binários como string.

        public static byte[] String2ByteArray(string str)
        {
            char[] chars = str.ToArray();
            byte[] bytes = new byte[chars.Length * 2];

            for (int i = 0; i < chars.Length; i++)
                Array.Copy(BitConverter.GetBytes(chars[i]), 0, bytes, i * 2, 2);

            return bytes;
        }

        public static string ByteArray2String(byte[] bytes)
        {
            char[] chars = new char[bytes.Length / 2];

            for (int i = 0; i < chars.Length; i++)
                chars[i] = BitConverter.ToChar(bytes, i * 2);

            return new string(chars);
        }
Marco Pardo
fonte
não tinha um. Mas essa função está sendo usada para transmissão binária em nossa rede da empresa e até agora 20 TB foram re e codificados corretamente. Então, para mim esta função funciona :)
Marco Pardo
1

Além da resposta selecionada, se você estiver usando .NET35 ou .NET35 CE, precisará especificar o índice do primeiro byte a decodificar e o número de bytes a decodificar:

string result = System.Text.Encoding.UTF8.GetString(byteArray,0,byteArray.Length);
Único
fonte
0

Experimente este aplicativo de console:

static void Main(string[] args)
{
    //Encoding _UTF8 = Encoding.UTF8;
    string[] _mainString = { "Héllo World" };
    Console.WriteLine("Main String: " + _mainString);

    //Convert a string to utf-8 bytes.
    byte[] _utf8Bytes = Encoding.UTF8.GetBytes(_mainString[0]);

    //Convert utf-8 bytes to a string.
    string _stringuUnicode = Encoding.UTF8.GetString(_utf8Bytes);
    Console.WriteLine("String Unicode: " + _stringuUnicode);
}
RM Shahidul Islam Shahed
fonte
0

Vi algumas respostas neste post e é possível ser considerado um conhecimento básico completo, pois há várias abordagens na programação em C # para resolver o mesmo problema. É necessário considerar apenas uma coisa sobre a diferença entre UTF-8 puro e UTF-8 com BOM .

Na semana passada, no meu trabalho, preciso desenvolver uma funcionalidade que produza arquivos CSV com BOM e outros CSVs com UTF-8 puro (sem BOM), cada tipo de codificação de arquivo CSV será consumido por diferentes APIs não padronizadas. A API leu UTF-8 com BOM e a outra API leu sem BOM. Eu preciso pesquisar as referências sobre esse conceito, lendo " Qual é a diferença entre UTF-8 e UTF-8 sem BOM? " A discussão do Stack Overflow e este link da Wikipedia " Byte order mark " para criar minha abordagem.

Finalmente, minha programação em C # para os dois tipos de codificação UTF-8 (com BOM e pura) precisava ser semelhante como este exemplo a seguir:

//for UTF-8 with B.O.M., equals shared by Zanoni (at top)
string result = System.Text.Encoding.UTF8.GetString(byteArray);

//for Pure UTF-8 (without B.O.M.)
string result = (new UTF8Encoding(false)).GetString(byteArray);
Antonio Leonardo
fonte