¿Por qué la pregunta "UTF-8 byte[] to string" sigue siendo relevante?
Imagina: has recibido un array de bytes de una solicitud de red, has leído un archivo binario o has deserializado datos de una API. Dentro hay texto normal en ruso, inglés o emojis. Pero C# solo ve byte[]. Tu tarea es convertir esos ceros y unos en una cadena string comprensible.
¿Qué podría ser más simple, verdad? Una sola llamada a un método y listo. Pero en Stack Overflow, la pregunta "How to convert UTF-8 byte[] to string" acumula miles de visitas y decenas de respuestas. ¿Por qué? Porque el diablo está en los detalles: codificación, rendimiento, seguridad y excepciones inesperadas.
En este artículo no solo te daremos código listo. Compararemos enfoques, mediremos la velocidad, discutiremos las trampas y elegiremos la mejor herramienta para cada tarea. Si programas en C# y trabajas con redes, archivos o serialización, este material es para ti.
El problema: byte[] no es una cadena
En C#, la cadena string se almacena en codificación UTF-16. Pero los bytes que recibiste probablemente están codificados en UTF-8 (el estándar de internet, JSON, la mayoría de los protocolos de texto). La conversión directa de tipos es imposible: el compilador dará un error.
Se necesita un decodificador que convierta una secuencia de bytes UTF-8 en caracteres UTF-16. Y aquí comienza lo interesante: el desarrollador tiene al menos tres caminos fundamentalmente diferentes.
Método 1: El clásico — Encoding.UTF8.GetString
La forma más obvia y recomendada por Microsoft es usar la clase estática System.Text.Encoding:
byte[] utf8Bytes = { 72, 101, 108, 108, 111, 32, 208, 191, 209, 128, 208, 176, 208, 178, 208, 176 }; // "Hello права"string result = Encoding.UTF8.GetString(utf8Bytes);Console.WriteLine(result); // Salida: Hello праваVentajas:
- Simplicidad: una sola línea de código.
- Soporte para todas las codificaciones, incluyendo UTF-8, UTF-16, ASCII, Latin-1.
- Manejo integrado de BOM (Byte Order Mark): si hay un marcador UTF-8 al inicio del array, se ignora.
- Seguridad: sin bloques
unsafe.
Desventajas:
- Cada llamada crea una nueva cadena y un búfer interno.
- Si los bytes están dañados o contienen una secuencia UTF-8 no válida, el método por defecto lanza una
DecoderFallbackException(a menos que se configure un fallback). - No es óptimo para arrays muy grandes (cientos de megabytes): doble copia de datos.
¿Cuándo usarlo?
En el 95% de los casos. Es el estándar de la industria. Si no estás escribiendo un analizador de alto rendimiento ni trabajas con gigabytes de registros, usa Encoding.UTF8.GetString.
Método 2: Rápido y peligroso — unsafe con punteros
Para quienes buscan velocidad y no temen al unsafe. La idea: sabemos que UTF-8 y UTF-16 son codificaciones diferentes, pero si el array solo contiene caracteres ASCII (códigos hasta 127), cada byte se puede "expandir" a un carácter de 2 bytes sin decodificación.
unsafe string UnsafeAsciiBytesToString(byte[] bytes){ fixed (byte* pBytes = bytes) { return new string((sbyte*)pBytes, 0, bytes.Length); }}¡Este código solo funciona para ASCII! Para texto en ruso (caracteres > 127), el resultado será basura. Pero para inglés puro, funciona 2-3 veces más rápido que Encoding.UTF8.GetString.
Ventajas:
- Gastos generales mínimos: sin copia, sin decodificación.
- Ideal para analizar encabezados HTTP, claves JSON (si son ASCII).
Desventajas:
- Peligroso para caracteres multibyte: corrupción de datos.
- Requiere permiso
unsafeen el proyecto (no siempre permitido). - No maneja