7.7. Más comprobaciones de errores: excepciones
El uso de "File.Exists" nos permite saber si el fichero existe, pero ese no es el único problema que podemos tener al acceder a un fichero. Puede ocurrir que no tengamos permiso para acceder al fichero, a pesar de que exista, o que intentemos escribir en un dispositivo que sea sólo de lectura (como un CD-ROM, por ejemplo).
Una forma más eficaz de comprobar si ha existido algún tipo de error es utilizar el manejo de "excepciones" que permiten los lenguajes modernos, como C#.
La idea es la siguiente: "intentaremos" dar una serie de pasos, y al final de todos ellos indicaremos qué pasos hay que dar en caso de que alguno no se consiga completar. Esto permite que el programa sea más legible que la alternativa "convencional", que consistía en: intentar un paso y comprobar errores; si todo era correcto, intentar otro paso y volver a comprobar errores; si todo seguía siendo correcto, intentar otro nuevo paso, y así sucesivamente.
La forma de conseguirlo es dividir en dos bloques las partes de programa que puedan dar lugar a error:
- En un primer bloque, indicaremos los pasos que queremos "intentar" (try).
- A continuación, detallaremos las posibles excepciones que queremos "interceptar" (catch), y lo que se debe hacer en ese caso.
Un primer ejemplo, que mostrara todo el contenido de un fichero de texto, y que en caso de error, se limitara a mostrar un mensaje de error y a abandonar el programa, podría ser:
/*---------------------------*/ /* Ejemplo en C# nº 75: */ /* ejemplo75.cs */ /* */ /* Excepciones y ficheros */ /* (1) */ /* */ /* Introduccion a C#, */ /* Nacho Cabanes */ /*---------------------------*/ using System; using System.IO; public class Ejemplo75 { public static void Main() { StreamReader fichero; string nombre; string linea; Console.WriteLine("Introduzca el nombre del fichero"); nombre = Console.ReadLine(); try { fichero = File.OpenText(nombre); do { linea = fichero.ReadLine(); if (linea != null) Console.WriteLine( linea ); } while (linea != null); fichero.Close(); } catch (Exception exp) { Console.WriteLine("Ha habido un error: {0}", exp.Message); return; } } }
El resultado, si ese fichero no existe, sería
Introduzca el nombre del fichero prueba Ha habido un error: No se pudo encontrar el archivo 'C:\Fuentes\nacho\prueba'.Pero en general, lo razonable no es interceptar "todas las excepciones a la vez", sino crear un análisis para cada caso, que permita recuperarse del error y seguir adelante, para lo que se suelen crear varios bloques "catch". Por ejemplo, en el caso de que queramos crear un fichero, podemos tener excepciones como éstas:
- El fichero existe y es de sólo lectura (se lanzará una excepción del tipo "IOException").
- La ruta del fichero es demasiado larga (excepción de tipo "PathTooLongException").
- El disco puede estar lleno (IOException).
Así, dentro de cada bloque "catch" podríamos indicar una excepción más concreta, de forma que el mensaje de aviso sea más concreto, o que podamos dar pasos más adecuados para solucionar el problema:
/*---------------------------*/ /* Ejemplo en C# nº 76: */ /* ejemplo76.cs */ /* */ /* Excepciones y ficheros */ /* (2) */ /* */ /* Introduccion a C#, */ /* Nacho Cabanes */ /*---------------------------*/ using System; using System.IO; public class Ejemplo76 { public static void Main() { StreamWriter fichero; string nombre; string linea; Console.Write("Introduzca el nombre del fichero: "); nombre = Console.ReadLine(); Console.Write("Introduzca la frase a guardar: "); linea = Console.ReadLine(); try { fichero = File.CreateText(nombre); fichero.WriteLine( linea ); fichero.Close(); } catch (PathTooLongException e) { Console.WriteLine("Nombre demasiado largo!"); } catch (IOException e) { Console.WriteLine("No se ha podido escribir!"); Console.WriteLine("El error exacto es: {0}", e.Message); } } }
Como la consola se comporta como un fichero de texto (realmente, como un fichero de entrada y otro de salida), se puede usar "try…catch" para comprobar ciertos errores relacionados con la entrada de datos, como cuando no se puede convertir un dato a un cierto tipo (por ejemplo, si queremos convertir a Int32, pero el usuario ha tecleado sólo texto).
Ejercicios propuestos:
- Un programa que pida al usuario el nombre de un fichero de origen y el de un fichero de destino, y que vuelque al segundo fichero el contenido del primero, convertido a mayúsculas. Se debe controlar los posibles errores, como que el fichero de origen no exista, o que el fichero de destino no se pueda crear.
- Un programa que pida al usuario un número, una operación (+, -, *, /) y un segundo número, y muestre el resultado de la correspondiente operación. Si se teclea un dato no numérico, el programa deberá mostrar un aviso y volver a pedirlo, en vez de interrumpir la ejecución.
- Un programa que pida al usuario repetidamente pares de números y la operación a realizar con ellos (+, -, *, /) y guarde en un fichero "calculadora.txt" el resultado de dichos cálculos (con la forma "15 * 6 = 90"). Debe controlar los posibles errores, como que los datos no sean numéricos, la división entre cero, o que el fichero no se haya podido crear.