1. Introducción
Las operaciones con archivos casi siempre están relacionadas con circunstancias externas al programa: el archivo puede ser eliminado, movido, bloqueado por otra aplicación, el usuario puede haberse quedado sin permisos o sin espacio en disco. Todo esto puede llevar a excepciones — situaciones especiales cuando la ejecución se interrumpe y se "lanza" un objeto de excepción (Exception). Si no atrapas y manejas esa excepción, tu programa terminará con error y mostrará al usuario un feo texto rojo en la consola (o, peor aún, se caerá silenciosamente).
En C# para manejar estas situaciones se usa el bloque try-catch (o, en buen plan, "trampa para errores"). Permite no solo "atrapar" el error, sino decidir calmadamente qué hacer: mostrar un mensaje amigable, ofrecer elegir otro archivo, escribir el error en el log o simplemente reintentar.
En aplicaciones reales
Si haces una calculadora de consola, quizá puedas prescindir de atrapar errores al trabajar con archivos. Pero si tu programa procesa documentos en una empresa o un juego que guarda el estado — no manejar esos errores es como andar en una cuerda floja sin arnés: tarde o temprano pasará algo.
2. Recordando el trabajo con excepciones
Sintaxis básica de try-catch
Antes de pasar a situaciones concretas con archivos, recordemos la sintaxis básica de la construcción try-catch (que ya vimos en las lecciones sobre excepciones):
try
{
// Aquí código que puede "lanzar" una excepción
}
catch (Exception ex)
{
// Aquí atrapamos todas las excepciones posibles... ¡Pero mejor no hacerlo así!
Console.WriteLine("Algo salió mal: " + ex.Message);
}
Dentro de try escribimos código potencialmente peligroso, y en catch qué hacer si algo va mal.
Broma de programador: "try-catch — es como una capa de invisibilidad digital para errores. El error está, pero no lo ves."
Excepciones de archivos
Cuando trabajas con archivos en .NET, con frecuencia encuentras excepciones — por ejemplo al crear streams, leer o escribir. Aquí algunos escenarios típicos y sus excepciones relacionadas:
- Archivo no encontrado → FileNotFoundException
- Sin acceso al archivo/directorio → UnauthorizedAccessException
- Problemas con la ruta (por ejemplo, caracteres no permitidos, ruta demasiado larga) → PathTooLongException, ArgumentException
- Archivo ya en uso por otro proceso → IOException
- Sin espacio en disco → IOException
La mayoría de las operaciones con archivos están relacionadas con subtipos de IOException. Todas ellas heredan del tipo base System.Exception.
3. Práctica: atrapando y manejando errores al trabajar con archivos
Veamos casos típicos con ejemplos de nuestra "aplicación en desarrollo": supongamos que intentamos leer un saludo desde un archivo, procesarlo y mostrarlo al usuario. Añadiremos comprobación de errores usando try-catch.
Ejemplo 1: Manejar "archivo no encontrado"
string filePath = "hello.txt";
try
{
string greeting = File.ReadAllText(filePath);
Console.WriteLine("Contenido del archivo: " + greeting);
}
catch (FileNotFoundException ex)
{
Console.WriteLine("¡Archivo no encontrado! Comprueba que el archivo " + filePath + " existe.");
// Podemos mostrar detalles adicionales
Console.WriteLine("Detalles técnicos: " + ex.Message);
}
Si el archivo "hello.txt" no existe, el programa no fallará, sino que mostrará un mensaje amigable. Así hacemos el programa resistente a los "errores tontos" del usuario.
Ejemplo 2: Violación de permisos
Tome una situación más complicada: el archivo existe, pero no tenemos permisos para leerlo (por ejemplo, alguien dio solo permisos de escritura o el archivo está en una carpeta protegida).
try
{
string secret = File.ReadAllText("C:\\Windows\\System32\\config.txt");
}
catch (UnauthorizedAccessException ex)
{
Console.WriteLine("¡Sin acceso al archivo! Intenta ejecutar el programa como administrador.");
Console.WriteLine("Razón técnica: " + ex.Message);
}
Ejemplo 3: General IOException
Algunos errores pueden venir por conflictos de bloqueo (otro proceso tiene el archivo abierto), falta de espacio en disco o problemas de hardware:
try
{
File.WriteAllText("important.txt", "¡Información importante!");
}
catch (IOException ex)
{
Console.WriteLine("Error al trabajar con el archivo: probablemente está siendo usado por otro programa o no hay suficiente espacio en disco.");
Console.WriteLine("Razón técnica: " + ex.Message);
}
4. Capturar múltiples excepciones: manejo selectivo
A veces necesitas reaccionar de forma distinta según el tipo de excepción. En .NET puedes poner varios bloques catch — de los más específicos a los más generales (si no, el compilador hará una protesta sonora italiana a tu código).
try
{
string content = File.ReadAllText("file.txt");
Console.WriteLine(content);
}
catch (FileNotFoundException ex)
{
Console.WriteLine("Archivo no encontrado.");
}
catch (UnauthorizedAccessException ex)
{
Console.WriteLine("¡Sin acceso al archivo!");
}
catch (IOException ex)
{
Console.WriteLine("Otro error de I/O: " + ex.Message);
}
Importante: si pones catch (Exception ex) primero, los demás bloques no tendrán sentido, porque el tipo base atrapará todo.
5. Try-catch anidados y reintentos
A veces quieres no solo manejar el error, sino dar al usuario la oportunidad de "arreglarlo" — por ejemplo, pedirle que introduzca la ruta de un archivo existente:
string filePath;
string content;
int attempts = 0;
const int maxAttempts = 3;
do
{
Console.Write("Introduce la ruta del archivo: ");
filePath = Console.ReadLine();
try
{
content = File.ReadAllText(filePath);
Console.WriteLine("Contenido del archivo:\n" + content);
break;
}
catch (FileNotFoundException)
{
Console.WriteLine("¡Archivo no encontrado! Intenta otra vez.");
}
catch (UnauthorizedAccessException)
{
Console.WriteLine("¡Sin acceso al archivo! Prueba con otro archivo.");
}
attempts++;
}
while (attempts < maxAttempts);
if (attempts == maxAttempts)
Console.WriteLine("Demasiados intentos fallidos.");
Este código es una pequeña "interfaz amigable" para un usuario que olvidó dónde guardó el archivo.
6. Errores típicos y particularidades: de la pereza a la conciencia
Un error muy común de principiantes (y hasta de desarrolladores veteranos) es atrapar todas las excepciones sin criterio, escribir simplemente catch (Exception) y mostrar "¡Ocurrió un error!", sin pensar en las causas. Ese enfoque es malo por varias razones. Primero, oculta fallos reales en la lógica de negocio de la aplicación. Segundo, otros errores no relacionados con archivos (por ejemplo, typos en el código o errores matemáticos) pueden tragarse y la búsqueda de la causa se alargará mucho.
Es mucho mejor —atrapar explícitamente solo los errores que sabes manejar de forma sensata. Si no está claro qué error ocurrió, es preferible dejar que "caiga" — es decir, no atraparlo: deja que la aplicación falle y muestre el stack trace para que puedas arreglarlo.
Particularidad: Algunas excepciones pueden tener causas anidadas (InnerException). Es útil analizarlas para diagnóstico más detallado, especialmente cuando escribes logs.
Otro detalle — si después de un bloque catch la vida normal del programa es imposible (por ejemplo, no se pudo abrir el archivo de configuración principal), puedes terminar la ejecución con return o incluso relanzar la excepción (throw;), para no crear "programas zombi" con funcionalidades a medias.
GO TO FULL VERSION