¿Cómo convertir el byte UTF-8 [] a cadena?


932

Tengo una byte[]matriz que se carga desde un archivo que conozco contiene UTF-8 .

En algún código de depuración, necesito convertirlo en una cadena. ¿Hay un trazador de líneas que haga esto?

Debajo de las cubiertas debe ser solo una asignación y una copia de memoria , por lo que incluso si no se implementa, debería ser posible.


55
"debería ser solo una asignación y una copia de memoria": no es correcto porque una cadena .NET está codificada en UTF-16. Un carácter Unicode puede ser una unidad de código UTF-8 o una unidad de código UTF-16. otro podría ser dos unidades de código UTF-8 o una unidad de código UTF-16, otro podría ser tres unidades de código UTF-8 o una unidad de código UTF-16, otro podría ser cuatro unidades de código UTF-8 o dos unidades de código UTF-16 . Una memcopy podría ampliarse pero no podría manejar la conversión de UTF-8 a UTF-16.
Tom Blodget

Respuestas:


1470
string result = System.Text.Encoding.UTF8.GetString(byteArray);

13
¿Cómo maneja las cadenas terminadas en nulo?
maazza

14
@maazza por razones desconocidas no lo hace en absoluto. Lo estoy llamando así System.Text.Encoding.UTF8.GetString(buf).TrimEnd('\0');.
Hi-Angel

15
@ Hola-Angel ¿Razón desconocida? La única razón por la que las cadenas terminadas en nulo alguna vez se hicieron populares fue el lenguaje C, e incluso eso fue solo debido a una rareza histórica (instrucciones de la CPU que trataban con cadenas terminadas en nulo). .NET solo usa cadenas terminadas en nulo cuando interopera con código que usa cadenas terminadas en nulo (que finalmente están desapareciendo). Es perfectamente válido que una cadena contenga caracteres NUL. Y, por supuesto, mientras que las cadenas terminadas en nulo son muy simples en ASCII (solo construya hasta obtener el primer byte cero), otras codificaciones, incluida UTF-8, no son tan simples.
Luaan

44
Una de las características hermosas de UTF-8 es que una secuencia más corta nunca es una subsecuencia de una secuencia más larga. Entonces, una cadena UTF-8 terminada en nulo es simple.
lavado el

10
Bueno, buena suerte desempacando si no tiene ASCII. Simplemente use Convert.ToBase64String.
Erik Bergstedt

323

Hay al menos cuatro formas diferentes de hacer esta conversión.

  1. GetString de codificación
    , pero no podrá recuperar los bytes originales si esos bytes tienen caracteres no ASCII.

  2. BitConverter.ToString
    La salida es una cadena delimitada "-", pero no hay un método incorporado de .NET para convertir la cadena de nuevo a una matriz de bytes.

  3. Convert.ToBase64String
    Puede convertir fácilmente la cadena de salida de nuevo a matriz de bytes mediante Convert.FromBase64String.
    Nota: La cadena de salida podría contener '+', '/' y '='. Si desea utilizar la cadena en una URL, debe codificarla explícitamente.

  4. HttpServerUtility.UrlTokenEncode
    Puede convertir fácilmente la cadena de salida a una matriz de bytes mediante HttpServerUtility.UrlTokenDecode. ¡La cadena de salida ya es compatible con URL! La desventaja es que necesita System.Webensamblaje si su proyecto no es un proyecto web.

Un ejemplo 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

77
LINQ it:var decBytes2 = str.Split('-').Select(ch => Convert.ToByte(ch, 16)).ToArray();
drtf

25

Una solución general para convertir una matriz de bytes a una cadena cuando no conoce la codificación:

static string BytesToStringConverted(byte[] bytes)
{
    using (var stream = new MemoryStream(bytes))
    {
        using (var streamReader = new StreamReader(stream))
        {
            return streamReader.ReadToEnd();
        }
    }
}

3
Pero esto supone que hay una BOM de codificación en el flujo de bytes o que está en UTF-8. Pero puede hacer lo mismo con la codificación de todos modos. No resuelve mágicamente el problema cuando no conoce la codificación.
Sebastian Zander

12

Definición:

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

Utilizando:

string result = input.ConvertByteToString();

9

La conversión de a byte[]a stringparece simple, pero es probable que cualquier tipo de codificación estropee la cadena de salida. Esta pequeña función simplemente funciona sin ningún resultado inesperado:

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

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

    return response;
}

Recibí System.FormatException usando su método cuando lo descomprimí con Convert.FromBase64String.
Erik Bergstedt

@ AndrewJE esto tomará incluso para calcular si tiene una matriz de bytes grande como la utilizada en las imágenes.
user3841581

7

Utilizando (byte)b.ToString("x2"), Salidasb4b5dfe475e58b67

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

}

4

También hay una clase UnicodeEncoding, bastante simple de usar:

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

Console.WriteLine("Data after decoding: {0}", ByteConverter.GetString(dataEncoded));

¿Pero no me parece UTF-8?
david.pfx

1
UnicodeEncodinges el peor nombre de la clase; Unicode no es una codificación en absoluto. Esa clase es en realidad UTF-16. La versión little-endian, creo.
Nyerguds

3

Alternativamente:

 var byteStr = Convert.ToBase64String(bytes);

2

Una línea única de Linq para convertir una matriz de bytes byteArrFilenameleída de un archivo a una cadena de terminación cero de estilo ascii C puro sería esta: útil para leer cosas como tablas de índice de archivos en formatos de archivo antiguos.

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

Utilizo '?'como char predeterminado para cualquier cosa que no sea puramente ascii aquí, pero eso se puede cambiar, por supuesto. Si quiere asegurarse de poder detectarlo, simplemente use'\0' , ya que TakeWhileal principio se asegura de que una cadena construida de esta manera no pueda contener '\0'valores de la fuente de entrada.


2

BitConverterLa clase se puede utilizar para convertir un byte[]a string.

var convertedString = BitConverter.ToString(byteAttay);

La documentación de la BitConverterclase se puede encontrar en MSDN


1
Esto convierte la matriz de bytes en una cadena hexadecimal que representa cada byte, que generalmente no es lo que desea al convertir bytes en una cadena. Si lo hace, entonces esa es otra pregunta, vea por ejemplo ¿Cómo convierte Byte Array a Cadena Hexadecimal, y viceversa? .
CodeCaster

No es lo que preguntó OP
Invierno

2

Que yo sepa, ninguna de las respuestas dadas garantiza un comportamiento correcto con terminación nula. Hasta que alguien me muestre de manera diferente, escribí mi propia clase estática para manejar esto con los siguientes 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);
}

La razón de esto startIndexfue en el ejemplo en el que estaba trabajando específicamente, necesitaba analizar byte[]un conjunto de cadenas terminadas en nulo. Se puede ignorar con seguridad en el caso simple


El mío lo hace, en realidad. byteArr.TakeWhile(x => x != 0)es una forma rápida y fácil de resolver el problema de terminación nula.
Nyerguds

1

hier es un resultado en el que no tuvo que molestarse con la codificación. Lo usé en mi clase de red y envié objetos binarios como una cadena con él.

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

No tenía uno. Pero esta función está en uso para la transmisión binaria en la red de nuestra compañía y hasta ahora 20TB fueron codificados correctamente. Entonces, para mí, esta función funciona :)
Marco Pardo

1

Además de la respuesta seleccionada, si está utilizando .NET35 o .NET35 CE, debe especificar el índice del primer byte para decodificar y el número de bytes para decodificar:

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

0

Prueba esta aplicación de consola:

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

0

Vi algunas respuestas en esta publicación y es posible que se considere un conocimiento base completo, porque tengo varios enfoques en la programación de C # para resolver el mismo problema. Solo una cosa que es necesario tener en cuenta es la diferencia entre UTF-8 puro y UTF-8 con BOM .

En la semana pasada, en mi trabajo, necesito desarrollar una funcionalidad que genere archivos CSV con BOM y otros CSV con UTF-8 puro (sin BOM), cada tipo de codificación de archivos CSV será consumido por diferentes API no estandarizadas, esa API leyó UTF-8 con BOM y la otra API leyó sin BOM. Necesito investigar las referencias sobre este concepto, leyendo " ¿Cuál es la diferencia entre UTF-8 y UTF-8 sin BOM? " Discusión de desbordamiento de pila y este enlace de Wikipedia " Marca de orden de bytes " para construir mi enfoque.

Finalmente, mi programación de C # para los dos tipos de codificación UTF-8 (con BOM y puro) tenía que ser similar a este ejemplo a continuación:

//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);
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.