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

BCS
fuente
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);
Zanoni
fuente
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
detale
fuente
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();
        }
    }
}
Nir
fuente
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();
Erçin Dedeoğlu
fuente
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;
}
AndrewJE
fuente
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;
    }

}
metadings
fuente
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));
PK
fuente
¿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);
Fehr
fuente
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.

Nyerguds
fuente
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

Sagar
fuente
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

Asimilador
fuente
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);
        }
Marco Pardo
fuente
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);
El único
fuente
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);
}
RM Shahidul Islam Shahed
fuente
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);
Antonio Leonardo
fuente