CodeGym /Cursos /C# SELF /Problemas con encoding mismatches y

Problemas con encoding mismatches y BOM

C# SELF
Nivel 37 , Lección 3
Disponible

1. ¿Por qué todo es tan complicado con las codificaciones?

Ya sabes que los archivos de texto son solo una secuencia de bytes. Y C# (y .NET en general) es una plataforma que quiere que todas las letras estén en su sitio. Parecería suficiente indicar la codificación al leer o escribir y todo funcionaría, pero el mundo real no es tan sencillo.

Razones de la confusión con las codificaciones:

  • Herencia histórica: Los archivos pueden crearse en distintos sistemas operativos y editores, cada uno con su codificación "por defecto".
  • Multiplataforma: Un archivo creado en Windows puede abrirse en Linux o Mac, donde la codificación "por defecto" es otra.
  • BOM (Byte Order Mark): Una "cabecera" especial del archivo que a veces está y a veces no. Afecta a cómo los programas interpretan el archivo.

2. ¿Qué es el BOM y para qué sirve?

Breve sobre BOM

BOM (Byte Order Mark) es una secuencia especial de bytes al inicio del archivo que le dice al programa: "¡Hola! Estoy en esta codificación, y así debes leer mis bytes".

  • BOM aparece más a menudo en archivos con codificaciones UTF-8, UTF-16 y UTF-32.
  • En UTF-8 el BOM es opcional. Su presencia o ausencia puede afectar cómo distintos programas leen el archivo.
Codificación BOM (vista hexadecimal) Bytes
UTF-8
EF BB BF
239 187 191
UTF-16 LE
FF FE
255 254
UTF-16 BE
FE FF
254 255
UTF-32 LE
FF FE 00 00
255 254 0 0
UTF-32 BE
00 00 FE FF
0 0 254 255

Dato curioso sobre las codificaciones: En ASCII y las codificaciones ANSI no se usa el BOM. Pero si apareciera ahí, sorprendería a los programas antiguos.

Ilustración: dónde está el BOM


+--------------------------+
| BOM |     TEXT BYTES     |
+--------------------------+
|EFBBBF|  48 65 6C 6C 6F   |  // "Hello" en UTF-8 con BOM
+--------------------------+

EF BB BF es el BOM para UTF-8. Está al principio del archivo.
48 65 6C 6C 6F son los bytes habituales del texto "Hello" en UTF-8 (sin BOM se verían exactamente igual).
En resumen: el archivo empieza con EF BB BF y luego viene el texto.

3. Desajustes de codificación: de dónde sale el «mojibake»

Escenario típico

  1. Guardas un archivo en UTF-8, pero sin BOM.
  2. Lo abres en un editor en Windows que esperaba Windows-1251 o UTF-8 con BOM.
  3. Como resultado — en vez de "¡Hola, mundo!" ves "Привет, РјРёСЂ!".

Por qué pasa esto

  • El programa piensa que el archivo está en una codificación, pero los bytes en realidad están en otra.
  • BOM ayuda a adivinar la codificación. Pero si no hay BOM, la detección suele ser por "ensayo y error". El resultado: «mojibake».

Ejemplos de escenarios de desajuste:

  • Lees un archivo en UTF-8 como Windows-1251 — todos los caracteres no ASCII se convierten en garabatos.
  • Lees un archivo UTF-8 con BOM como "UTF-8 puro" — normalmente va bien, pero algunos programas viejos mostrarán los primeros caracteres como símbolos raros.
  • Escribes un archivo con BOM, pero se esperaba sin él — el software externo que no soporta BOM puede "tropezar".

4. Cómo la codificación y el BOM afectan al trabajo con streams

Ejemplo: escribir y leer archivos con codificaciones distintas

// Escribimos el archivo en UTF-8 con BOM
using var writer = new StreamWriter("test_utf8_bom.txt", false, new UTF8Encoding(true));
writer.WriteLine("¡Hola, mundo!");

new UTF8Encoding(true) — añade el BOM.

// Escribimos el archivo en UTF-8 sin BOM
using var writer = new StreamWriter("test_utf8_no_bom.txt", false, new UTF8Encoding(false));
writer.WriteLine("¡Hola, mundo!");

new UTF8Encoding(false) — sin BOM.

// Lectura del archivo indicando la codificación explícitamente
using var reader = new StreamReader("test_utf8_no_bom.txt", new UTF8Encoding(false));
string line = reader.ReadLine();
Console.WriteLine(line);

Si el archivo está en UTF-8 sin BOM, indicar la codificación explícitamente garantiza una lectura correcta.

Error típico

Cuando no indicas la codificación al leer, StreamReader intentará adivinar: primero comprobará el BOM, si existe; si no — usará la codificación del sistema por defecto (en Windows suele ser Windows-1251 para la versión en ruso, en Linux/Mac suele ser UTF-8).

5. Qué hacer ante desajustes de codificación

Has visto «mojibake». Tus acciones:

  1. Comprueba con qué codificación se creó el archivo.
    Abre el archivo en un editor que muestre la codificación (por ejemplo, Notepad++).
  2. Especifica la codificación explícitamente al leer/escribir.
    No confíes en "por defecto", aunque parezca que siempre funcionó:
using var reader = new StreamReader("data.txt", Encoding.UTF8);

Ten en cuenta el BOM.

  • Si otro software requiere BOM — añádelo (ver new UTF8Encoding(true)).
  • Si no lo requiere — escribe sin BOM (ver new UTF8Encoding(false)).

Ejemplo: codificación incorrecta al leer

// Archivo creado en UTF-8, lo leemos como Windows-1251
using var reader = new StreamReader("test_utf8_no_bom.txt", Encoding.GetEncoding(1251));
var text = reader.ReadToEnd();
Console.WriteLine(text); // "¡Hola, mundo!" se verá corrupto

6. Matices útiles

El BOM en proyectos reales y en entrevistas

Si trabajas en un proyecto donde hay que guardar configs, logs o exportar datos, conviene decidir desde el principio una codificación y documentarla. Puede parecer una tontería, pero cuando esos archivos los leen otros programas o personas, el malentendido en la codificación causa muchos problemas.

En entrevistas el tema del BOM y de los "símbolos raros al inicio del archivo" es casi una pregunta clásica. Es importante no solo saber qué es el BOM, sino explicar por qué su presencia (o ausencia) importa en integraciones y cómo se relaciona con indicar la codificación explícitamente.

Sé especialmente cuidadoso al intercambiar datos con sistemas en otras OS o escritos en otros lenguajes. En unos sitios el BOM es obligatorio y en otros rompe el parser. Si no lo prevés, puede ser difícil de depurar.

Recomendaciones y buenas prácticas

  • Indica siempre la codificación al trabajar con archivos (nunca confíes en "por defecto").
  • Si necesitas BOM — usa new UTF8Encoding(true), si no — new UTF8Encoding(false).
  • Comprueba archivos en editores que soporten varias codificaciones (por ejemplo, Notepad++, Visual Studio Code).
  • Si recibes un archivo de fuera — pregunta a tus compañeros o revisa la documentación para saber en qué codificación fue creado.
  • Si hay que convertir la codificación o quitar el BOM — hazlo de forma explícita.

Qué ven distintos programas

Archivo Codificación de escritura Abrir como Qué veremos
UTF-8 con BOM
UTF-8 + BOM
UTF-8
OK ("¡Hola, mundo!")
UTF-8 sin BOM
UTF-8
Windows-1251
Mojibake
Win-1251
Win-1251
UTF-8
Mojibake
UTF-8 con BOM
UTF-8 + BOM
ASCII
Los primeros bytes se ven alterados

7. Cómo comprobar y eliminar el BOM

Ejemplo: comprobar la presencia de BOM

byte[] bytes = File.ReadAllBytes("test_utf8_bom.txt");
// Comprobamos los primeros 3 bytes
if (bytes.Length >= 3 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF)
{
    Console.WriteLine("¡BOM encontrado! Es UTF-8 con BOM.");
}
else
{
    Console.WriteLine("BOM ausente.");
}

Ejemplo: eliminar el BOM (si por algún motivo estorba)

if (bytes.Length >= 3 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF)
{
    // Escribimos el archivo sin los primeros 3 bytes
    File.WriteAllBytes("no_bom.txt", bytes.Skip(3).ToArray());
}

8. Errores típicos y cómo solucionarlos

Muchos desarrolladores noveles se sorprenden cuando su programa empieza a "fallar" al trabajar con archivos de texto. Normalmente el problema aparece cuando el programa que escribió el archivo usó una codificación (o un modo con BOM) y el que lo lee usa otra. Por ejemplo, si guardas en UTF-8 sin BOM y lo lees en Windows cuya codificación por defecto es Windows-1251, no es de extrañar que los caracteres queden como garabatos. Es crucial siempre indicar la codificación explícitamente. Si el archivo se comparte entre diferentes programas o plataformas, usa un formato universal — UTF-8 (o UTF-8 con BOM si el software externo lo exige).

Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION