1. Concepto de codificación (encoding)
Empecemos por la pregunta principal: ¿qué es una codificación?
Imagina que has llegado a una conferencia internacional. Cada uno habla su propio idioma, pero todos quieren entenderse. Para eso hace falta un intérprete que sepa que la palabra "hello" en inglés es "privet" en ruso y "hola" en español. En el mundo de los ordenadores, la codificación es ese intérprete.
Una codificación — es una forma de representar caracteres como bytes
El ordenador es simple: solo entiende ceros y unos, es decir, bits y bytes. Las personas, en cambio, quieren ver letras, cifras, emojis e incluso — ¡horror! — caracteres chinos. Para que el ordenador pueda “escribir” un carácter, hay que acordar a qué secuencia de bytes corresponderá cada carácter.
La codificación (encoding) es el conjunto de reglas por el que los caracteres (letras, cifras, signos de puntuación, emojis, etc.) se convierten en bytes para su almacenamiento y transmisión, y a la inversa: los bytes se convierten en caracteres para su visualización.
Ejemplo: la letra 'A' cirílica (U+0410) en distintas codificaciones
- En la codificación UTF-8 la letra 'A' cirílica (U+0410) se codifica con dos bytes: 0xD0 0x90.
- En Windows-1251 esa misma letra — un solo byte: 0xC0.
- En cambio, la 'A' latina en casi todas las codificaciones populares — es 0x41.
Si lees un archivo con una codificación incorrecta, los caracteres se convertirán en «mojibake» (símbolos incomprensibles o signos de interrogación).
2. Para qué sirven las codificaciones
¿Por qué no podemos simplemente almacenar las letras tal cual?
Porque el ordenador solo entiende números (ceros y unos). Qué número corresponde a qué letra — esa es precisamente la esencia de la codificación.
Ejemplo: «Privet» en el disco
Cuando escribes en un archivo la palabra "Privet", para el ordenador es simplemente una secuencia de bytes. Cómo interpretar esos bytes — depende de la codificación.
- Si el archivo está en UTF-8, entonces la «P» cirílica (U+041F) son dos bytes, la «r» cirílica (U+0440) también son dos, y así sucesivamente.
- Si está en Windows-1251, cada letra es un byte, pero con otros valores.
¿Dónde hacen falta las codificaciones?
- Al guardar texto en un archivo: para poder leer correctamente los bytes después.
- Al leer texto de un archivo: para convertir los bytes de nuevo en letras.
- Al enviar texto por la red (por ejemplo, HTTP, correo electrónico).
- Al trabajar con bases de datos: allí también hay que saber en qué codificación se guarda el texto.
Si no indicas la codificación...
Es como abrir un texto en un idioma desconocido e intentar leerlo. Las probabilidades aumentan si sabes qué idioma es. Y si no lo sabes — en el mejor de los casos no entenderás nada; en el peor, obtendrás galimatías.
3. Problemas sin la codificación correcta
«Mojibake» y pérdida de datos
La queja más habitual de los programadores novatos (y no tan novatos): «¿Por qué en lugar de "Privet" veo "Привет" o incluso solo signos de interrogación?»
Esto sucede cuando el archivo se grabó con una codificación y se lee con otra. Por ejemplo, el archivo se creó en un Windows antiguo con Windows-1251 y lo abres en Linux, donde por defecto es UTF-8. O al revés.
Ejemplo
- Se grabó el archivo en Windows-1251: el byte para la letra «P» cirílica (U+041F) — 0xCF.
- Se abrió en UTF-8: el programa espera que la cirílica sean dos bytes y recibe uno. Todo falla.
Pérdida de datos
Si al guardar un carácter no está soportado por la codificación elegida (por ejemplo, intentas guardar un emoji en ASCII), desaparecerá o se sustituirá por un signo de interrogación. Todo lo que no “cabe” en la codificación se pierde.
Problemas al intercambiar archivos
Los archivos guardados con una codificación pueden mostrarse incorrectamente en otros equipos si allí la codificación por defecto es distinta. Esto sucede a menudo al intercambiar archivos entre Windows y Linux o al abrir archivos antiguos.
4. Codificación en Java: representación interna y externa
Dentro de la JVM: siempre Unicode (UTF-16)
En Java las cadenas (String) dentro del programa siempre se almacenan en Unicode (más precisamente, en UTF-16). Esto significa que puedes asignar a las variables cadenas en cualquier idioma del mundo, y Java lo “digerirá” sin problemas.
String hello = "Hola, mundo! 😀";
En la memoria de la JVM este texto se almacena como un conjunto de números de 16 bits (char), donde a cada carácter le corresponde su código en la tabla Unicode.
Dato curioso
En Java un símbolo de tipo char ocupa 16 bits (2 bytes). Pero algunos caracteres (por ejemplo, ideogramas raros o emojis) requieren ya dos char — son las «pares sustitutos».
En E/S: ¡la codificación importa!
Cuando lees o escribes cadenas hacia el exterior (archivos, red), Java debe convertir la representación interna (UTF-16) en una secuencia de bytes. Ahí es donde entra la codificación.
- Si no indicas explícitamente la codificación, Java usa la propia del sistema por defecto (en Windows en ruso puede ser Windows-1251, en Linux — UTF-8).
- Esto es peligroso: en otro ordenador el resultado puede ser distinto.
Ejemplo: lectura y escritura de archivo sin indicar la codificación
// ¡Mala práctica! No se especifica la codificación.
FileReader reader = new FileReader("data.txt");
FileWriter writer = new FileWriter("data.txt");
En este caso, Java utiliza la codificación del sistema. Si el archivo se grabó en otro sistema — obtendrás «mojibake».
Buena práctica: indicar siempre la codificación
// ¡Bien! La codificación se indica explícitamente.
BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream("data.txt"), StandardCharsets.UTF_8));
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream("data.txt"), StandardCharsets.UTF_8));
5. Ilustración breve: qué pasa al trabajar con codificaciones
Esquema: el camino de una cadena desde el archivo hasta el programa y vuelta
[Archivo en disco (bytes, codificación X)]
|
V
[Java lee los bytes y con la codificación X los convierte en String (UTF-16)]
|
V
[Trabajas con la cadena en el programa]
|
V
[Java escribe el String a bytes usando la codificación Y]
|
V
[Archivo en disco (bytes, codificación Y)]
Si X y Y coinciden — todo bien. Si son diferentes — pueden aparecer problemas.
6. Breve historia de las codificaciones (para curiosos)
ASCII
ASCII es una de las codificaciones más antiguas: un byte por carácter, solo alfabeto inglés, dígitos y signos básicos. Cualquier otro alfabeto — fuera.
Windows-1251, ISO-8859-1 y otros «veteranos»
Son codificaciones de un byte para distintos conjuntos de letras: cirílico, latín, griego, etc. Cada cual elegía la suya, y empezó el caos.
Unicode y la familia UTF
- Unicode — la tabla global para los caracteres del mundo.
- UTF-8, UTF-16, UTF-32 — distintas formas de representar caracteres Unicode en bytes.
- UTF-8 se ha convertido en el estándar para la Web, archivos e intercambio entre sistemas.
7. Práctica: cómo influye la codificación al trabajar con archivos
Veamos un pequeño ejemplo de escritura y lectura de cadenas con codificaciones distintas.
Ejemplo: escribir y leer con codificaciones diferentes
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
public class EncodingDemo {
public static void main(String[] args) throws IOException {
String text = "Hola, mundo! 😀";
// Escribimos el archivo en UTF-8
try (Writer writer = new OutputStreamWriter(
new FileOutputStream("utf8.txt"), StandardCharsets.UTF_8)) {
writer.write(text);
}
// Ahora intentemos leerlo con una codificación incorrecta
try (Reader reader = new InputStreamReader(
new FileInputStream("utf8.txt"), Charset.forName("Windows-1251"))) {
int c;
while ((c = reader.read()) != -1) {
System.out.print((char) c);
}
}
// ¡Aparecerá mojibake!
}
}
Conclusión: Si las codificaciones no coinciden — el texto se distorsionará.
8. Codificación e integración con otros sistemas
En proyectos reales los archivos suelen intercambiarse entre distintos programas, escritos en distintos lenguajes y ejecutándose en diferentes SO. Cada uno puede esperar su propia codificación. Si no se acuerda de antemano — aparecerán «mojibake» y errores difíciles de detectar. Un caso típico: la base de datos guarda el texto en UTF-8, pero el programa lee el archivo de origen como Windows-1251 y lo carga en la BD — los caracteres distorsionados están garantizados.
9. Errores típicos al trabajar con codificaciones
Error n.º 1: no se indica la codificación al leer/escribir un archivo.
Como resultado, el programa funciona “en mi ordenador”, pero en el del compañero — «mojibake».
Error n.º 2: uso de constructores obsoletos (FileReader, FileWriter).
Siempre usan la codificación del sistema — una trampa para principiantes.
Error n.º 3: codificación incorrecta del archivo de origen.
Si el archivo se grabó con una codificación y se lee con otra, parte de los caracteres se distorsionará o se sustituirá por signos de interrogación.
Error n.º 4: pérdida de caracteres al cambiar de codificación.
Si la codificación de destino no soporta todos los caracteres (por ejemplo, ASCII en lugar de UTF-8), parte del texto simplemente desaparecerá.
GO TO FULL VERSION