1. Introducción
Seamos sinceros desde el principio: si alguna vez has visto en lugar de texto en ruso algo como Привет, ya eres víctima de una codificación incorrecta. Esto sucede cuando el archivo se guardó con una codificación y se lee con otra. Por ejemplo, el archivo se guardó como UTF-8 y se lee como Windows-1251, o al revés.
Java, por defecto, utiliza la codificación del sistema, que puedes averiguar así:
System.out.println(System.getProperty("file.encoding"));
En un equipo puede ser UTF-8, en otro — Windows-1251, y en algún otro — ISO-8859-1. Por eso es mejor indicar siempre la codificación de forma explícita. Es especialmente importante si trabajas con datos multilingües, si los archivos se usarán en distintos ordenadores o se abrirán en otros programas, o si necesitas que tu código se comporte igual en cualquier entorno, y no solo en tu máquina.
Clase Charset: tu aliado en el mundo de las codificaciones
En Java, para trabajar con codificaciones se usa la clase java.nio.charset.Charset. Permite indicar la codificación por nombre (por ejemplo, "UTF-8") o utilizar constantes estándar (StandardCharsets.UTF_8).
Ejemplos de codificaciones estándar:
| Codificación | Constante de Java |
|---|---|
| UTF-8 | |
| UTF-16 | |
| ISO-8859-1 | |
| Windows-1251 | |
Es preferible utilizar las constantes: hay menos probabilidades de equivocarse en el nombre y no aparecerá UnsupportedCharsetException.
2. Lectura de archivos indicando la codificación
Método antiguo:
import java.io.*;
import java.nio.charset.StandardCharsets;
BufferedReader reader = new BufferedReader(
new InputStreamReader(
new FileInputStream("example.txt"),
StandardCharsets.UTF_8 // <-- Especificamos explícitamente la codificación
)
);
Método moderno:
import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.io.BufferedReader;
BufferedReader reader = Files.newBufferedReader(
Paths.get("example.txt"),
StandardCharsets.UTF_8 // <-- Especificamos explícitamente la codificación
);
Se recomienda usar el segundo método — es más corto, más seguro y combina bien con try-with-resources.
Ejemplo: leer una línea de un archivo
try (BufferedReader reader = Files.newBufferedReader(
Paths.get("hello.txt"),
StandardCharsets.UTF_8)) {
String line = reader.readLine();
System.out.println("Leído: " + line);
}
Por qué es importante: Si el archivo se guardó en UTF-8 y lo lees como Windows-1251, los caracteres cirílicos se corromperán. Si indicas la codificación correcta, el texto se leerá correctamente en cualquier SO.
3. Escritura de archivos indicando la codificación
Método antiguo:
import java.io.*;
import java.nio.charset.StandardCharsets;
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream("example.txt"),
StandardCharsets.UTF_8 // <-- Especificamos explícitamente la codificación
)
);
Método moderno:
import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.io.BufferedWriter;
BufferedWriter writer = Files.newBufferedWriter(
Paths.get("example.txt"),
StandardCharsets.UTF_8 // <-- Especificamos explícitamente la codificación
);
Ejemplo: escribir una línea en un archivo
try (BufferedWriter writer = Files.newBufferedWriter(
Paths.get("hello.txt"),
StandardCharsets.UTF_8)) {
writer.write("¡Hola, mundo!");
}
Resultado: El archivo se guardará en UTF-8, y se podrá abrir correctamente en cualquier editor que admita UTF-8.
4. Detalles útiles
Cómo conocer las codificaciones compatibles
import java.nio.charset.Charset;
public class ListCharsets {
public static void main(String[] args) {
System.out.println("Codificaciones disponibles:");
Charset.availableCharsets().forEach((name, charset) -> System.out.println(name));
}
}
Consejo: si utilizas una codificación exótica (por ejemplo, para ideogramas chinos antiguos o emoticonos marcianos), comprueba si tu JVM la admite.
Uso de try-with-resources: no olvides cerrar los flujos
Al trabajar con archivos, es importante cerrar los flujos para evitar fugas de recursos. El código Java moderno utiliza la construcción try-with-resources:
try (BufferedReader reader = Files.newBufferedReader(path, charset)) {
// Trabajamos con el archivo
}
El flujo se cerrará automáticamente, incluso si ocurre un error.
Recomendaciones
- Es mejor especificar siempre la codificación al leer y escribir archivos, incluso si estás seguro de que «por defecto todo funciona».
- Usa UTF-8 para archivos nuevos — es el estándar de facto, especialmente si trabajas con web, JSON, XML, o quieres que tus archivos sean legibles en todas partes.
- Para archivos antiguos (por ejemplo, exportaciones de 1C, bases de datos antiguas, CSV de Windows) usa la codificación en la que fueron guardados (por ejemplo, Windows-1251, ISO-8859-1).
- No uses clases obsoletas donde la codificación no se especifica explícitamente: FileReader/FileWriter. En su lugar, utiliza InputStreamReader/OutputStreamWriter con codificación explícita o métodos de Files.
- Para archivos grandes usa almacenamiento intermedio (BufferedReader/BufferedWriter) para no consumir toda la memoria.
5. Errores comunes al trabajar con codificaciones
Error n.º 1: No se especifica la codificación al leer/escribir el archivo.
Si no se indica la codificación, Java usa la del sistema por defecto ("file.encoding"). En tu máquina todo funciona, y en la de tu compañero — «caracteres raros».
Error n.º 2: No coinciden las codificaciones de lectura y escritura.
El archivo se guardó con una codificación y se lee con otra. Por ejemplo, el archivo se escribió en UTF-8 y se lee como Windows-1251 — la escritura cirílica se distorsiona.
Error n.º 3: Uso de las clases obsoletas FileReader/FileWriter.
Estas clases no permiten especificar la codificación de forma explícita — no se recomienda usarlas. En su lugar, usa InputStreamReader/OutputStreamWriter indicando la codificación o los métodos de Files.
Error n.º 4: Error en el nombre de la codificación.
Por ejemplo, escribiste "utf8" en lugar de "UTF-8" o "win1251" en lugar de "Windows-1251". Java lanzará UnsupportedCharsetException.
Error n.º 5: Flujo sin cerrar — el archivo no se escribió.
Si no usas try-with-resources o no cierras el flujo explícitamente, parte de los datos puede no llegar al disco.
GO TO FULL VERSION