1. Síntomas de los errores
En un mundo ideal, los programadores siempre saben en qué codificación se guarda un archivo y la indican correctamente al leerlo. Pero la realidad es un mundo donde los archivos circulan entre Windows, Linux, servidores, editores, y cada uno interpreta los bytes a su manera. Como resultado, nos encontramos con los siguientes síntomas:
- «Mojibake» — en lugar del texto esperado vemos símbolos extraños, signos de interrogación, cuadraditos o una secuencia de letras que no se parece a ningún idioma del mundo.
- Pérdida de caracteres — parte del texto desaparece o se sustituye por ?.
- Excepciones — por ejemplo, MalformedInputException, cuando Java no puede “digerir” los bytes en la codificación elegida.
- Errores de análisis — el programa no puede procesar correctamente el archivo porque las palabras clave o las estructuras se dañan debido a la distorsión del texto.
He aquí un ejemplo clásico de «mojibake» al leer un archivo en cirílico con una codificación incorrecta:
Esperábamos: ¡Hola, mundo!
Obtenido: Привет, мир
No es un idioma nuevo, sino el resultado de que los bytes se interpretaron con un “diccionario” equivocado.
2. Por qué surgen los errores: la raíz del problema
El archivo se guarda en una codificación y se lee en otra
Supongamos que alguien guardó un archivo en Windows-1251 y tú lo abres en UTF-8. Java intenta decodificar honestamente los bytes según las reglas de UTF-8, pero el resultado es un sinsentido porque los valores de los bytes no coinciden con los esperados.
Uso de la codificación del sistema «por defecto»
Si no indicas la codificación explícitamente, Java usa la del sistema — la que esté configurada en tu equipo. En Windows con configuración regional rusa puede ser Windows-1251, en Linux — UTF-8, en Mac — también UTF-8. Un archivo que se abre perfectamente en tu equipo puede volverse ilegible en el de un colega con otro SO.
Uso de constructores obsoletos
En versiones antiguas de Java (y en algunos manuales) es frecuente ver construcciones con FileReader/FileWriter, que usan la codificación del sistema y no te dan control — esto es una trampa y una fuente de «mojibake».
FileReader reader = new FileReader("file.txt");
FileWriter writer = new FileWriter("file.txt");
Presencia o ausencia de BOM (Byte Order Mark)
Algunas codificaciones (por ejemplo, UTF-8 con BOM o UTF-16) añaden al inicio del archivo unos bytes especiales para señalar su naturaleza. Si el programa no espera BOM o, al contrario, lo espera pero no lo encuentra, pueden surgir problemas: o bien se distorsionan los primeros caracteres del archivo, o bien el archivo no se reconoce en absoluto.
3. Cómo se manifiestan los errores: análisis práctico
Ejemplo 1: archivo con cirílico guardado en Windows-1251 y leído como UTF-8
import java.nio.file.*;
import java.nio.charset.*;
public class EncodingDemo {
public static void main(String[] args) throws Exception {
Path path = Paths.get("russian.txt");
// El archivo está en Windows-1251; lo leemos como UTF-8 — ¡habrá mojibake!
try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
System.out.println(reader.readLine());
}
}
}
Como resultado, en lugar de «¡Hola, mundo!» verás un conjunto de caracteres extraños.
Ejemplo 2: el archivo está en UTF-8 y se lee como ISO-8859-1
try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.ISO_8859_1)) {
System.out.println(reader.readLine());
}
Resultado: Todos los caracteres no ASCII se convertirán en basura o se sustituirán por ?.
Ejemplo 3: excepción al leer el archivo
Si los bytes no se ajustan a las reglas de la codificación elegida, Java puede lanzar una excepción:
Exception in thread "main" java.nio.charset.MalformedInputException: Input length = 1
at java.base/sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
...
Esto significa que Java encontró un byte que no puede interpretarse correctamente en la codificación seleccionada.
4. Diagnóstico: cómo entender qué falla con la codificación
Comprueba la codificación del archivo
- En editores como Notepad++, VS Code o Sublime Text normalmente puedes ver o cambiar la codificación del archivo (suele estar en la barra inferior).
- En Linux puedes obtener una pista sobre la codificación con un comando (aunque no siempre es 100% exacto):
file nombre_de_archivo.txt
Comprueba la codificación del sistema de Java
Imprime en la consola el valor de la propiedad file.encoding:
System.out.println(System.getProperty("file.encoding"));
Usa datos de prueba
Crea un archivo pequeño con distintos caracteres (cirílicos, latinos, símbolos especiales, emoji), intenta leerlo con diferentes codificaciones y observa cuándo el resultado coincide con lo esperado.
Indica siempre explícitamente la codificación
En cuanto veas en el código lectura/escritura de archivos sin indicar la codificación — es motivo para desconfiar. Por ejemplo, usa Files.newBufferedReader(..., StandardCharsets.UTF_8) en lugar de los valores «por defecto».
5. Buenas prácticas: cómo no caer en la trampa
Regla n.º 1:
SIEMPRE indica explícitamente la codificación al trabajar con archivos, especialmente si el archivo se usará en distintos equipos, en diferentes SO o se enviará por la red.
Regla n.º 2:
Usa codificaciones modernas — ante todo UTF-8 (StandardCharsets.UTF_8). Solo si hay requisitos especiales (por ejemplo, integración con un sistema antiguo) utiliza otras codificaciones.
Regla n.º 3:
Evita las clases FileReader y FileWriter (no permiten especificar la codificación); en su lugar usa InputStreamReader, OutputStreamWriter o métodos de Files con un Charset explícito.
Regla n.º 4:
¡Verifica el resultado! Abre los archivos escritos en editores con soporte para distintas codificaciones para asegurarte de que el texto se ve correctamente.
6. Particularidades y matices: BOM, XML, JSON y otros casos «divertidos»
BOM (Byte Order Mark): a veces un archivo en UTF-8 comienza con bytes “invisibles” (EF BB BF). La mayoría de programas modernos los ignoran, pero algunos pueden mostrar «mojibake» al inicio de la línea o rechazar el archivo (por ejemplo, analizadores antiguos de XML/JSON).
XML/HTML: a veces al inicio del archivo hay una línea como <?xml version="1.0" encoding="UTF-8"?>. Indica al programa en qué codificación esperar los bytes. Pero si la codificación real no coincide con la declarada — de nuevo «mojibake».
JSON: por estándar debe estar en UTF-8, pero si el archivo se creó en Windows-1251, el analizador producirá un error o datos distorsionados.
GO TO FULL VERSION