«Cadenas» y «bytes»: ¿por qué es un dolor de cabeza eterno para el programador?
\nImagínese esta situación: está escribiendo una aplicación de red en C#, enviando datos al servidor, y a la salida obtiene un galimatías de caracteres. O cifra una contraseña, y al otro lado no pueden descifrarla. ¿Le suena familiar? La raíz del mal a menudo radica en una conversión incorrecta de una cadena a un array de bytes (y viceversa).
\nLa pregunta «Converting string to byte array in C#» en Stack Overflow ha acumulado miles de visitas no por casualidad. Es la base sobre la que se sustentan el trabajo con archivos, la criptografía, la serialización y la comunicación en red. Sin comprender este tema, pisará el mismo rastrillo una y otra vez. Aclaremos de una vez por todas cómo hacerlo correctamente.
\n\n¿Por qué no se puede simplemente tomar y convertir una cadena en bytes?
\n¿Un enfoque ingenuo sería usar BitConverter.GetBytes() para un carácter? No. El problema es que una cadena es una abstracción compuesta por caracteres (char, 2 bytes en C#). Mientras que un array de bytes son datos sin procesar que dependen de la codificación.
Un mismo carácter «A» en la codificación UTF-8 ocupará 1 byte, en UTF-16 ocupará 2 bytes, y en UTF-32 ocupará 4 bytes. Si elige la codificación incorrecta, los datos se perderán. Recuerde la regla principal: especifique siempre la codificación explícitamente.
\n\nEl método más popular: Encoding.UTF8.GetBytes()
\nEsto es lo que usará en el 90% de los casos. UTF-8 es el estándar de facto para la web, JSON y la mayoría de las API.
\n\nusing System;\nusing System.Text;\n\nclass Program\n{\n static void Main()\n {\n string original = "¡Hola, mundo! 🌍";\n \n // Convertimos la cadena en un array de bytes (UTF-8)\n byte[] utf8Bytes = Encoding.UTF8.GetBytes(original);\n \n // Conversión inversa (para verificar)\n string restored = Encoding.UTF8.GetString(utf8Bytes);\n \n Console.WriteLine($"Cadena original: {original}");\n Console.WriteLine($"Array de bytes (longitud {utf8Bytes.Length}): {BitConverter.ToString(utf8Bytes)}");\n Console.WriteLine($"Cadena restaurada: {restored}");\n }\n}\n\nResultado de la ejecución:
\nCadena original: ¡Hola, mundo! 🌍\nArray de bytes (longitud 18): D0-9F-D1-80-D0-B8-D0-B2-D0-B5-D1-82-2C-20-D0-BC-D0-B8-D1-80-21-20-F0-9F-8C-8D\nCadena restaurada: ¡Hola, mundo! 🌍\n\nTenga en cuenta: el emoji «🌍» ocupa 4 bytes (F0-9F-8C-8D). UTF-8 puede trabajar con cualquier carácter Unicode, a diferencia de las codificaciones obsoletas.
\n\nOtras codificaciones populares
\n- \n
- Encoding.ASCII — solo caracteres de 7 bits (0-127). No es adecuado para cirílico o caracteres especiales: todo lo que esté por encima de 127 se convertirá en '?' \n
- Encoding.Unicode (también conocido como UTF-16LE) — se usa internamente en C# para almacenar cadenas. Cada carácter ocupa 2 bytes (o 4 para pares sustitutos). \n
- Encoding.UTF32 — cada carácter ocupa estrictamente 4 bytes. Consume muchos recursos, pero es predecible. \n
- Encoding.Default — codificación del sistema (ANSI). ¡Evítela! Es diferente en diferentes ordenadores. \n
Conversión con BitConverter y MemoryStream
\nA veces es necesario obtener una representación «cruda» de la cadena como un array de caracteres (char). Esto no es lo mismo que los bytes en una codificación, pero puede ser útil para trabajo de bajo nivel.
\n\nstring text = "C#";\n// Obtenemos un array de char\nchar[] chars = text.ToCharArray();\n// Convertimos cada char en 2 bytes (Little-Endian)\nbyte[] rawBytes = new byte[chars.Length * sizeof(char)];\nBuffer.BlockCopy(chars, 0, rawBytes, 0, rawBytes.Length);\n\nConsole.WriteLine(BitConverter.ToString(rawBytes)); // 43-00-23-00\n\nEste método produce un array en codificación UTF-16LE (como se almacena en memoria). Úselo solo si sabe exactamente lo que está haciendo.
\n\nCaso especial: Base64
\nEs