1. UTF-8 — el rey de las codificaciones modernas
En el trabajo de un programador te encontrarás con archivos, protocolos de red, bases de datos y servicios web donde se utilizan distintas codificaciones. Si no sabes en qué se diferencia UTF-8 de ISO-8859-1, es fácil caer en una trampa: tu código funcionará «en mi ordenador», pero fallará en el de un colega en Francia o en la nube, donde el sistema por defecto es otro.
Hoy veremos tres codificaciones principales que aparecen en la vida real de un desarrollador Java:
- UTF-8 — estándar universal moderno.
- UTF-16 — formato interno de las cadenas en Java y muy habitual en Windows.
- ISO-8859-1 (Latin-1) — una codificación de un byte antigua pero aún presente para idiomas de Europa occidental.
¡Vamos a conocerlas mejor!
¿Qué es?
UTF-8 (Unicode Transformation Format, 8-bit) es una codificación capaz de representar cualquier carácter de la enorme tabla Unicode (incluye escritura cirílica, caracteres chinos, emoji e incluso escrituras antiguas poco comunes). Y lo hace de forma ingeniosa: para los caracteres más populares (letras inglesas, dígitos, signos de puntuación) usa solo 1 byte. Para otros — 2, 3 o incluso 4 bytes.
Hecho: Todos los sitios modernos, la mayoría de archivos JSON y XML, e incluso los fuentes de Java usan por defecto UTF-8.
¿Cuántos bytes necesita un carácter?
- Caracteres ASCII (letras inglesas, dígitos, signos de puntuación) — 1 byte.
- Caracteres cirílicos y europeos con diacríticos — 2 bytes.
- Ideogramas chinos, japoneses y coreanos — 3 bytes.
- Súper exóticos, emoji — 4 bytes.
Ejemplo:
| Símbolo | Código en Unicode | UTF-8 (en bytes) |
|---|---|---|
| A | |
|
| Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Ya | |
|
| € | |
|
| 😀 | |
|
¿Por qué UTF-8 es excelente?
- Retrocompatible con ASCII: si el archivo contiene solo caracteres ingleses, se ve exactamente igual que en ASCII.
- Compacidad: para textos cortos en inglés, un archivo en UTF-8 tendrá el tamaño mínimo.
- Internacionalidad: admite todos los idiomas del mundo, incluidos los emoji.
- Estándar para la web: HTML, CSS, JSON, XML, JavaScript — todo esto es por defecto UTF-8.
Ejemplo de uso en Java
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
public class Utf8Demo {
public static void main(String[] args) throws Exception {
// Escritura de una cadena en un archivo en UTF-8
String text = "¡Hola, mundo! 😀";
Files.write(Paths.get("utf8.txt"), text.getBytes(StandardCharsets.UTF_8));
// Lectura del archivo en UTF-8
String read = Files.readString(Paths.get("utf8.txt"), StandardCharsets.UTF_8);
System.out.println(read); // Mostrará: ¡Hola, mundo! 😀
}
}
Aquí primero codificamos explícitamente la cadena en UTF-8 antes de escribir, y luego indicamos la codificación al leer. Gracias a ello el texto se conserva y se recupera sin distorsiones, incluso si contiene emoji o caracteres de distintos idiomas.
¿Cuándo usar UTF-8?
Siempre, salvo que tengas una razón de mucho peso para elegir otra cosa. Es la opción universal para todas las aplicaciones modernas.
2. UTF-16 — el formato interno de Java
UTF-16 es otra codificación de la familia Unicode. A diferencia de UTF-8, suele usar 2 bytes por carácter. Así es como Java almacena las cadenas (String) y los caracteres (char) dentro de la JVM. Pero hay un matiz: algunos caracteres (por ejemplo, ideogramas raros o emoji) requieren 4 bytes (un «par sustituto»).
¿Dónde se utiliza UTF-16?
- Dentro de Java: todas las cadenas y caracteres son UTF-16.
- Windows: muchos archivos de sistema en Windows usan UTF-16 (por ejemplo, el Bloc de notas guarda por defecto en UTF-16 LE).
- Algunos protocolos y formatos: por ejemplo, XML puede estar en UTF-16.
Ejemplo: cómo se ve una cadena en UTF-16
| Símbolo | Código en Unicode | UTF-16 (bytes) | Comentario |
|---|---|---|---|
| A | |
|
2 bytes |
| Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Ya | |
|
2 bytes |
| € | |
|
2 bytes |
| 😀 | |
|
4 bytes (par sustituto) |
Ejemplo de uso en Java
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
public class Utf16Demo {
public static void main(String[] args) throws Exception {
String text = "¡Hola, mundo! 😀";
// Escritura de la cadena en un archivo con la codificación UTF-16
Files.write(Paths.get("utf16.txt"), text.getBytes(StandardCharsets.UTF_16));
// Lectura del contenido del archivo indicando UTF-16
String read = Files.readString(Paths.get("utf16.txt"), StandardCharsets.UTF_16);
System.out.println(read); // Salida correcta de la cadena original
}
}
Punto clave: al escribir y leer hay que indicar la misma codificación. Si escribes en UTF-16 y lees por defecto (por ejemplo, en UTF-8), aparecerá una «ensalada» de caracteres.
Particularidades de UTF-16
- Longitud fija para la mayoría de caracteres: 2 bytes.
- Pares sustitutos: algunos caracteres (por ejemplo, emoji) requieren 4 bytes.
- Byte Order Mark (BOM): al principio del archivo a menudo se añade una «cabecera» especial que indica el orden de los bytes (LE — little endian, BE — big endian). Java suele reconocer el BOM automáticamente.
- No compatible con ASCII: si abres un archivo UTF-16 en un editor que espera ASCII o UTF-8, verás muchos ceros y símbolos extraños.
¿Cuándo usar UTF-16?
- Si trabajas con sistemas o archivos muy específicos que requieren exactamente UTF-16 (p. ej., integración con programas de Windows).
- Para aplicaciones y archivos habituales — mejor usa UTF-8.
4. ISO-8859-1 (Latin-1) — un saludo desde el pasado
ISO-8859-1, o Latin-1, es una codificación de un solo byte creada en los lejanos años 80. Admite 256 caracteres: alfabeto inglés, letras de Europa occidental con diacríticos (é, ü, ç, etc.), signos de puntuación y símbolos especiales.
Hecho: En esta codificación no hay caracteres cirílicos, griegos, árabes, chinos ni otros no latinos.
¿Dónde aparece ISO-8859-1?
- En archivos y programas antiguos (especialmente en Europa).
- En algunas bases de datos y protocolos «por defecto».
- En cabeceras HTTP (por estándar, los datos de texto sin codificación indicada se consideran ISO-8859-1, aunque en la práctica es raro).
Ejemplo: cómo se ve una cadena en ISO-8859-1
| Símbolo | Código en Unicode | ISO-8859-1 (byte) | Comentario |
|---|---|---|---|
| A | |
|
Igual que en ASCII |
| é | |
|
Francés |
| ü | |
|
Alemán |
| Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Cyrillic letter Ya | |
— | ¡No existe tal carácter! |
Ejemplo de uso en Java
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.nio.charset.Charset;
public class Latin1Demo {
public static void main(String[] args) throws Exception {
String text = "Bonjour, ça va? Café!"; // Texto en francés
Files.write(Paths.get("latin1.txt"), text.getBytes(StandardCharsets.ISO_8859_1));
// Lectura del archivo en ISO-8859-1
String read = Files.readString(Paths.get("latin1.txt"), StandardCharsets.ISO_8859_1);
System.out.println(read); // ¡Todo se lee correctamente!
// Intentemos escribir caracteres cirílicos (o cualquier carácter fuera de Latin-1)
String cyrillic = "¡Hola, mundo! 😀";
try {
Files.write(Paths.get("badlatin1.txt"), cyrillic.getBytes(StandardCharsets.ISO_8859_1));
} catch (Exception e) {
System.out.println("Error: ¡no es posible escribir cirílico en ISO-8859-1!");
}
}
}
La codificación ISO-8859-1 (Latin-1) solo admite caracteres de Europa occidental — por ejemplo, letras con acentos del francés, alemán o español. Por eso el texto en francés se escribe y se lee sin problemas.
Sin embargo, el cirílico no está presente en esta codificación, y al intentar escribirlo se produce un error o pérdida de caracteres. Por eso, para textos multilingües es mejor usar UTF-8 o UTF-16, que cubren un conjunto de caracteres mucho mayor.
Particularidades de ISO-8859-1
- Limitación por idiomas: solo idiomas de Europa occidental.
- 1 byte por carácter: compacto, pero muy limitado.
- Guardar caracteres «ajenos» provoca distorsión: si intentas guardar cirílico o ideogramas, se convertirán en signos de interrogación o basura.
¿Cuándo usar ISO-8859-1?
- Solo si te integras con un sistema o base de datos muy antiguo que requiera exactamente esta codificación.
- Para tareas modernas — no recomendado.
5. Matices útiles
Tabla comparativa de codificaciones
| Codificación | Bytes por carácter | Idiomas | Compatibilidad con ASCII | Dónde se usa |
|---|---|---|---|---|
|
1-4 | Todos | Completa | Web, Java, JSON, XML, Linux |
|
2 o 4 | Todos | No | Dentro de Java, Windows, XML |
|
1 | Europa occidental | Completa | Programas antiguos, bases de datos, HTTP |
¿Cómo elegir la codificación?
- UTF-8 — tu elección para el 99 % de las tareas. Compatible con ASCII, admite todos los idiomas, tamaño mínimo para texto en inglés, estándar para la web y Java.
- UTF-16 — úsalo solo si lo exige la especificación o la integración con programas de Windows.
- ISO-8859-1 — solo para compatibilidad con sistemas antiguos. Nunca lo uses para almacenar cirílico, griego, árabe, etc.
¿Cómo saber en qué codificación está un archivo?
- Abre el archivo en un editor que muestre la codificación (por ejemplo, Notepad++, VS Code).
- Si ves «caracteres raros», intenta abrir el archivo con otra codificación.
- En la terminal de Linux puedes usar el comando file nombre_de_archivo — a veces sugiere la codificación.
¿Cómo establecer la codificación en Java?
Utiliza las clases del paquete java.nio.charset:
- StandardCharsets.UTF_8
- StandardCharsets.UTF_16
- StandardCharsets.ISO_8859_1
O por nombre de codificación:
Charset windows1251 = Charset.forName("Windows-1251");
Charset utf8 = Charset.forName("UTF-8");
6. Práctica: ¿qué pasa si te equivocas de codificación?
Hagamos un pequeño experimento. Escribiremos una cadena en UTF-8 y luego intentaremos leerla como ISO-8859-1:
import java.nio.file.*;
import java.nio.charset.*;
public class EncodingMismatchDemo {
public static void main(String[] args) throws Exception {
String text = "¡Hola, mundo!"; // Texto en español
// Escribimos como UTF-8
Files.write(Paths.get("utf8demo.txt"), text.getBytes(StandardCharsets.UTF_8));
// Leemos como ISO-8859-1 (¡INCORRECTO!)
String wrong = Files.readString(Paths.get("utf8demo.txt"), StandardCharsets.ISO_8859_1);
System.out.println("Lectura incorrecta: " + wrong);
// Ahora leemos correctamente
String correct = Files.readString(Paths.get("utf8demo.txt"), StandardCharsets.UTF_8);
System.out.println("Lectura correcta: " + correct);
}
}
Resultado:
- En el primer caso verás «caracteres raros» — un conjunto de símbolos extraños.
- En el segundo caso — texto correcto.
7. Errores típicos al trabajar con codificaciones
Error n.º 1: leer un archivo con la codificación incorrecta. Si el archivo está escrito en UTF-8 y lo lees como ISO-8859-1 o Windows-1251, todos los caracteres no ASCII se convertirán en basura. El clásico: «en mi ordenador todo funciona, pero en el de mi colega — no».
Error n.º 2: intentar guardar caracteres «ajenos» en una codificación de un byte. Si intentas guardar cirílico o ideogramas en ISO-8859-1, Java los sustituirá por signos de interrogación o dará un error. Los datos se perderán de forma irreversible.
Error n.º 3: usar la codificación del sistema «por defecto». En algunos métodos de Java (por ejemplo, new FileReader("file.txt")) no se indica explícitamente la codificación — se usa la del sistema. En un ordenador puede ser UTF-8, en otro — Windows-1251, y en un tercero — algo exótico. Por eso, utiliza siempre métodos donde puedas indicar la codificación explícitamente.
Error n.º 4: abrir un archivo UTF-16 como UTF-8. Un archivo escrito en UTF-16, si se abre como UTF-8, contendrá muchos ceros y símbolos extraños, porque los bytes se interpretarán de forma incorrecta.
GO TO FULL VERSION