1. Jerarquía de excepciones de entrada/salida
En Java, al trabajar con archivos y otros recursos externos, casi siempre hay que lidiar con las llamadas excepciones de entrada/salida. Son objetos que se lanzan (throw) cuando algo va mal al leer o escribir datos. Por ejemplo, si el archivo no existe, no hay permisos o el disco de repente «se cansó».
Los protagonistas de nuestra lección
En Java hay toda una jerarquía de este tipo de excepciones. Aquí están las principales:
- IOException — la clase base para todos los errores de entrada/salida. Si algo va mal con archivos, flujos o red, casi siempre «tiene la culpa» ella (o alguno de sus numerosos descendientes).
- FileNotFoundException — «hijo» de IOException, que aparece cuando intentas abrir un archivo que no existe o la ruta es incorrecta.
Otros derivados:
- EOFException — también «hijo» directo de IOException. Indica que, durante la lectura, llegamos inesperadamente al final del archivo.
- MalformedInputException — «nieto»: hereda de CharacterCodingException, que a su vez hereda de IOException. Este error aparece si el archivo no puede interpretarse correctamente con la codificación indicada (por ejemplo, se esperaba "UTF-8" y llegó una secuencia corrupta).
- Y también hay SocketException, ZipException y otros «parientes» especializados, cada uno con su ámbito de responsabilidad. Cuanto más profundo en la jerarquía, más estrecha y específica es la situación.
Esquema simplificado:
java.lang.Exception
└── java.io.IOException
├── java.io.FileNotFoundException
├── java.io.EOFException
├── java.nio.charset.MalformedInputException
└── ... (otros)
Dato interesante:
En Java casi todas las operaciones con archivos exigen declarar o manejar IOException: son las llamadas excepciones comprobadas (checked exceptions). ¡El compilador no te dejará olvidarte de gestionar los errores!
2. Cuándo y por qué surgen estas excepciones
Apertura de un archivo inexistente
El caso más frecuente: intentas abrir un archivo y no está. Es como llegar a una parada y que el autobús ni siquiera exista en el horario.
FileInputStream fis = new FileInputStream("abracadabra.txt"); // ¡Pum! FileNotFoundException
Intento de escribir en un archivo sin permisos
Si intentas escribir un archivo en una carpeta donde no tienes permisos, obtendrás FileNotFoundException o IOException (según la situación).
FileOutputStream fos = new FileOutputStream("/system/secret.txt"); // ¡Pum! FileNotFoundException o IOException
Errores de lectura/escritura por daño del medio
A veces el archivo existe, pero el disco está dañado, el archivo lo usa otro programa o se cortó la luz de repente: en ese caso recibirás IOException con distintos mensajes.
Otras causas
- El archivo está abierto solo para lectura y tú intentas escribir.
- La ruta al archivo es demasiado larga o contiene caracteres no permitidos.
- El archivo está siendo utilizado por otro proceso.
- El disco está lleno.
- Otro proceso elimina el archivo entre la comprobación y su uso.
3. Manejo con try-catch
Siempre que trabajes con archivos, flujos o red, usa try-catch. Es como un airbag: si algo va mal, el programa no se caerá y podrá reaccionar correctamente.
¿Cómo capturar las excepciones correctamente?
En Java hay que capturar las excepciones más concretas antes que las generales. Si pones primero un catch general (IOException e), las más específicas, como FileNotFoundException, no se ejecutarán: no se llegará a ellas.
Estructura correcta:
try {
// Trabajo con el archivo
} catch (FileNotFoundException e) {
// Manejo de la situación "archivo no encontrado"
} catch (IOException e) {
// Manejo de otros errores de entrada/salida
}
¿Por qué?
Porque FileNotFoundException es un caso particular de IOException. Si capturas antes el caso general, el particular no «llegará» a su catch.
Ejemplo de código: manejo de errores al abrir un archivo
import java.io.*;
public class FileReaderExample {
public static void main(String[] args) {
String filename = "notes.txt";
try {
BufferedReader reader = new BufferedReader(new FileReader(filename));
String line = reader.readLine();
System.out.println("Primera línea del archivo: " + line);
reader.close();
} catch (FileNotFoundException e) {
System.out.println("Archivo no encontrado: " + filename);
} catch (IOException e) {
System.out.println("Error al leer el archivo: " + e.getMessage());
}
}
}
Ten en cuenta:
Aunque hayas comprobado que el archivo existe, deja siempre try-catch: el archivo puede desaparecer en cualquier momento (por ejemplo, si otro proceso lo elimina).
4. Práctica: escribimos código con manejo de errores
Crearemos ejemplos sencillos y haremos que reaccionen correctamente a la ausencia de archivo y otros errores.
Paso 1: intentemos abrir un archivo inexistente
import java.io.*;
public class NotesApp {
public static void main(String[] args) {
String filename = "my_notes.txt";
try {
BufferedReader reader = new BufferedReader(new FileReader(filename));
String line;
System.out.println("Tus notas:");
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
reader.close();
} catch (FileNotFoundException e) {
System.out.println("¡Ups! No se encontró el archivo de notas: " + filename);
System.out.println("Consejo: crea el archivo o comprueba el nombre.");
} catch (IOException e) {
System.out.println("Se produjo un error al leer el archivo: " + e.getMessage());
}
}
}
Paso 2: añadamos el manejo para escribir el archivo
import java.io.*;
public class NotesWriter {
public static void main(String[] args) {
String filename = "my_notes.txt";
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(filename, true)); // append: true
writer.write("¡Nueva nota!\n");
writer.close();
System.out.println("¡La nota se ha añadido correctamente!");
} catch (IOException e) {
System.out.println("Error al escribir en el archivo: " + e.getMessage());
}
}
}
Paso 3: ejemplo universal con registro (logging) de errores
import java.io.*;
public class SafeFileCopier {
public static void main(String[] args) {
String source = "source.txt";
String target = "target.txt";
try {
BufferedReader reader = new BufferedReader(new FileReader(source));
BufferedWriter writer = new BufferedWriter(new FileWriter(target));
String line;
while ((line = reader.readLine()) != null) {
writer.write(line);
writer.newLine();
}
reader.close();
writer.close();
System.out.println("¡El archivo se copió correctamente!");
} catch (FileNotFoundException e) {
System.out.println("Archivo no encontrado: " + e.getMessage());
} catch (IOException e) {
System.out.println("Error de entrada/salida: " + e.getMessage());
}
}
}
Consejo:
En aplicaciones reales conviene registrar los errores no solo en pantalla, sino también en un archivo o bitácora, para poder averiguar después qué salió mal exactamente.
5. Tabla: principales excepciones de E/S
| Excepción | ¿Cuándo ocurre? | ¿Cómo manejarla? |
|---|---|---|
|
Archivo no encontrado, la ruta no existe, no hay permisos | Informar al usuario, comprobar ruta/permisos y crear el archivo si es necesario |
|
Fin de archivo inesperado durante la lectura | Informar de corrupción/incompletitud; intentar recuperar los datos parcialmente |
|
Error general de entrada/salida (disco, permisos, bloqueo) | Revisar los detalles, finalizar la operación correctamente y reintentar si es posible |
|
Codificación o estructura del archivo incorrecta | Informar de la corrupción; probar otra codificación/origen |
6. Errores típicos al manejar excepciones de E/S
Error n.º 1: capturar solo la Exception general. Es muy tentador escribir simplemente catch (Exception e), pero entonces no podrás distinguir qué salió mal exactamente. Es mejor capturar primero las excepciones concretas (FileNotFoundException) y después la general IOException.
Error n.º 2: no cerrar los flujos en caso de error. Si has abierto un archivo y luego se produce una excepción, el flujo puede quedar sin cerrar. Usa try-with-resources o cierra los recursos en finally.
Error n.º 3: ignorar los mensajes de las excepciones. No muestres simplemente «¡Error!», muestra los detalles: e.getMessage(). Eso ayuda a entender más rápido qué salió mal.
Error n.º 4: no manejar FileNotFoundException al escribir. Muchos piensan que FileNotFoundException es solo para lectura. En realidad puede surgir también al escribir (ruta incorrecta, falta de permisos para crear el archivo, etc.).
Error n.º 5: no comprobar los permisos de acceso. Si el programa se ejecuta con permisos limitados, muchas operaciones con archivos pueden fallar. Tenlo siempre en cuenta e informa al usuario.
GO TO FULL VERSION