Juan Carlos Castro http://consultasjava.tripod.com [email protected] Teoría Manejo de Excepciones Algunas operaciones en Java producen errores en tiempo de ejecución que si no se tratan correctamente pueden afectar de manera importante el funcionamiento del programa. Ejemplos de estas situaciones ocurren al tratar de hacer una división entre cero (DivisionByZeroException), tratar de leer de un archivo que no se pudo abrir (IOException), o hacer un URL mal hecho (MalFormedURLException). Cómo saber cuándo atrapar una excepción Las excepciones no ocurren siempre y tienen que ser atrapadas solamente cuando sea necesario. El programador puede darse cuenta de esto en el API o con la ayuda del compilador. En el API los métodos que tiran una excepción llevan la palabra clave throws y un nombre de Excepción para indicar que cualquier llamada a este método puede provocar una excepción de dicho tipo. Si el programador no se diera de cuenta el compilador se encargará de solicitarle que la atrape. Por ejemplo para leer un archivo se utiliza la clase FileReader la cual recibe en su constructor el nombre de un archivo. ¿Qué sucedería si el archivo no existe?. Leyendo en el API vemos la definición para este constructor. public FileReader(String fileName)throws FileNotFoundException Es decir para crear un FileReader hay que atrapar la Excepción FileNotFountException. Sin embargo un programador no experimentado podría codificar un código como el siguiente: public StringBuffer leerArchivo(String fileName){ StringBuffer resultado = new StringBuffer(); FileReader fr = new FileReader(fileName); // resto de instrucciones de lectura … return resultado; } Al tratar de compilarlo el compilador reporta los siguientes errores: java:7: unreported exception java.io.FileNotFoundException; must be caught or declared to be thrown FileReader fr = new FileReader(fileName); Cómo atrapar una excepción El código para el manejo de excepciones es bastante sencillo y consta de dos bloques fijos (try-catch) y de uno opcional (finally) que independientemente que la operación falle o no siempre se ejecuta. El bloque try es donde se intenta hacer aquello que puede fallar o aquello que tira una excepción. En el caso anterior aquí iría la creación del objeto FileReader. try{ FileReader fr = new FileReader(“miarchivo.txt”); System.out.println(“Hasta aquí todo bien =)”); } El bloque catch es donde se atrapan los errores. Va después del catch y su sintaxis tiene la peculiaridad de que recibe un tipo de excepción y una variable del tipo donde queda atrapada esta. catch(IOException ex){ System.out.println(“Fallo al abrir archivo:”+ex.toString()); } El bloque finally es opcional pero debe ir justo después del catch finally{ System.out.println(“Este bloque siempre se ejecuta completamente”); } Por lo tanto los bloques try-catch-finally para manejar excepciones se asemejan mucho al siguiente: try{ FileReader fr = new FileReader(“miarchivo.txt”); System.out.println(“Hasta aquí todo bien =)”); } catch(IOException ex){ System.out.println(“Fallo al abrir archivo:”+ex.toString()); } finally{ System.out.println(“Este bloque siempre se ejecuta completamente”); } Lectura y Escritura de Archivos El manejo de entrada y salida se maneja con la ayuda de las clases del paquete java.io.*. Para realizar operaciones básicas de lectura y escritura se utilizarán las siguientes clases: • FileReader • BufferedReader • FileWriter • BufferedWriter FileReader FileReader es un objeto que hereda de InputStreamReader, quien a su vez hereda de Reader. Un objeto Reader es un puente entre flujos de bytes y flujos de caracteres. Esto quiere decir que convierte los bytes leídos de algún flujo (entrada estándar, archivos) en bytes acorde a la codificación de caracteres del sistema operativo (ASCII,Unicote). FileReader además hace las operaciones básicas para abrir el archivo y dejarlo listo para lectura. Cada lectura sobre el archivo mueve el puntero que lleva la posición que es leída. BufferedReader BufferedReader recibe en su constructor un objeto de tipo Reader. BufferedReader se encarga de hacer lecturas de varios bytes y los deja en un lugar en memoria read(char []buff, int off, int len). BufferedReader también puede realizar lecturas por líneas devolviendo un String que contiene la línea de un archivo mediante el método readLine(). Ejemplo: lectura con zonas de memoria de 4Kb El siguiente método deja en un StringBuffer (java.util) la lectura de un archivo, leyendo en cada ciclo 4096 bytes (4 * 1024 bytes). public StringBuffer leerArchivo4096(String fileName){ StringBuffer sb = new StringBuffer(); try{ int read = 0; FileReader fr = new FileReader(fileName); BufferedReader br = new BufferedReader(fr); char area[] = new char[4096]; while(readed != -1){ read = br.read(area,0,4096); sb.append(new String(area,0,read)); } br.close(); } catch(Exception ex){ } return sb; } FileWriter FileWriter es un objeto que hereda de OutputStreamWriter, quien a su vez hereda de Writer. Un objeto Writer es un puente entre flujos de caracteres y flujos de bytes. Esto quiere decir que convierte los caracteres que van a ser escritos (entrada estándar, archivos) en bytes acorde a la codificación de caracteres del sistema operativo (ASCII, Unicode). FileWriter además hace las operaciones básicas para abrir el archivo y dejarlo listo para escritura. Cada escritura sobre el archivo mueve el puntero que lleva la posición que es leída. BufferedWriter BufferedWriter recibe en su constructor un objeto de tipo Writer, el cual utilizará para realizar las escrituras. En cada escritura se ponen los bytes que son almacenados en el buffer y cuando este se llena son escritos en memoria. Para poner el buffer en disco es necesario utilizar el método flush. Escritura por líneas /** Este método permite o bien escribir al final de un documento(con true) * en su argumento booleano o sobrescribirlo (con false en el booleano) */ public void write(String fileName,String Text,boolean writingMode){ try{ StringTokenizer TokenText = new StringTokenizer(Text,"\n",false); FileWriter fw = null; if(writingMode){ fw = new FileWriter(fileName,true); } else fw = new FileWriter(fileName); BufferedWriter writer = new BufferedWriter(fw); while(TokenText.hasMoreTokens()){ String temp = TokenText.nextToken(); writer.write(temp,0,temp.length()); writer.newLine(); } writer.flush(); writer.close(); } catch(IOException ex){} } Práctica 1. Haga una clase llamada ArchivoDeTexo (indispensable que se llame así). 2. Añada las siguientes propiedades al objeto ArchivoDeTexto: a. Un String llamado buffer que contiene el texto del archivo. La idea es que una vez que se lee del archivo el programador puede obtener el contenido del archivo sin realizar otra lectura. Esta variable es privada. b. Un objeto llamado file, que contiene el objeto de tipo File al que está asociado este objeto. El propósito es utilizar dicho objeto para obtener datos del archivo, tamaño, nombre, etc. Esta variable también debe ser privada. c. Un String llamado about que da una descripción del autor de la clase, con el fin de evitar el uso indebido de su clase por parte de otras personas. Dicho String debe ser privado. 1. Haga un constructor para la clase que reciba un objeto File, al cual hará referencia la variable File de esta clase. 2. Haga un constructor para la clase que reciba un String con una ruta de archivo e inicialice la variable file de esta clase. 3. Haga un método llamado getPath() que devuelva la ruta del archivo. 4. Haga un método llamado getSize() que devuelva el tamaño del archivo. 5. Sobrescriba el método toString() de la clase Object de manera que al invocarlo devuelva la ruta del archivo y el tamaño. 6. Haga un método llamado getBuffer() que devuelva el contenido de la variable buffer. 7. Haga un método llamado setBuffer(String nuevoTexto) que establezca el contenido del buffer. 8. Haga un método llamado read() que devuelva y deje en buffer el contenido del archivo. 9. Haga un método llamado write() que escriba el contenido de la variable buffer en disco. 10. Haga un método llamado getAuthorDescription() que devuelva una descripción del autor de la clase. Variable about. 11. Haga un método llamado setBufferAndSave(String newText) que modifique el buffer y guarde en disco. 12. Haga un método llamado setBufferAndSaveAs(String newText,File newFile) que modifique el buffer, y guarde el contenido en un archivo distinto. 13. Añada las siguientes opciones al block de notas de la semana pasada: a. Abrir: Muestra el contenido del archivo en el block de notas. b. Guardar: Guarda el contenido de lo que está escrito en el TextArea. c. Guardar Como: Guarda el contenido del TextArea en otro archivo. d. Un menú about que diga cuál versión de ArchivoDeTexto está utilizando el editor. 1. Generar el API para este objeto con javadoc. 2. Intercambiarlo con otras personas y probarlo.