En Java hay muchas clases para leer y escribir archivos (u otros dispositivos de E/S). Están reunidos en la biblioteca java.io.
Vamos a empezar como siempre con un pequeño ejemplo funcional y en seguida nos
meteremos en el necesario camino de las excepciones...
// archivo: Ejemplo9.java - compilar con "javac Ejemplo9.java", etc. etc. import java.io.*; public class Ejemplo9 { public static void main(String args[]) throws FileNotFoundException,IOException { FileInputStream fptr; DataInputStream f; String linea = null; fptr = new FileInputStream("Ejemplo9.java"); f = new DataInputStream(fptr); do { linea = f.readLine(); if (linea!=null) System.out.println(linea); } while (linea != null); fptr.close(); } }
(Caramba! ¿Qué hace ese throws ahí?)
El programa de ejemplo simplemente lee un archivo de texto y lo muestra en pantalla, algo así como el type del DOS o el cat de Unix.
Dejemos por ahora el throws FileNotFoundException,IOException
y vamos al código.
fptr = new FileInputStream("Ejemplo9.java");
La clase FileInputStream (descendiente de InputStream) nos sirve para referirnos a archivos o conexiones (sockets) de una máquina. Podemos accederlos pasando un String como aquí, un objeto de tipo File o uno de tipo FileDescriptor, pero en esencia es lo mismo. Al crear un objeto de este tipo estamos "abriendo" un archivo, clásicamente hablando.
Si el archivo no existe (por ejemplo reemplacen "Ejemplo9.java" por alguna otra cosa, como "noexiste.txt"), al ejecutarlo nos aparece un error:
C:\java\curso>java Ejemplo9 java.io.FileNotFoundException: noexiste.txt at java.io.FileInputStream.<init>(FileInputStream.java:51) at Ejemplo9.main(Ejemplo9.java:9)
(Caramba! ¿Dónde vi ese FileNotFoudException antes?)
Justamente, cuando el archivo al que quiero acceder no existe, Java "lanza" una excepción. Esto es, un aviso de que algo falló y, si no se toma ninguna acción, detiene el programa.
La clase FileInputStream puede "lanzar" (throws) la excepción FileNotFoundException.
¿Cómo capturar y tratar las excepciones? En seguida; primero terminemos con nuestro
programa.
f = new DataInputStream(fptr);
La clase DataInputStream nos permite leer, en forma independiente del hardware, tipos de datos de una "corriente" (stream) que, en este caso, es un archivo. Es descendiente de FilterInputStream e implementa DataInput, una interface.
Al crear un objeto de tipo DataInputStream lo referimos al archivo, que le pasamos como parámetro (fptr); esta clase tiene toda una serie de métodos para leer datos en distintos formatos.
En nuestro programa usamos uno para leer líneas, que devuelve null cuando se
llega al final del archivo o un String con el contenido de la
línea:
do { linea = f.readLine(); System.out.println(linea); } while (linea != null);
En seguida de leer la línea la imprimimos, y repetimos esto mientras no nos devuelva null.
Al final, cerramos el archivo:
fptr.close();
Tanto readLine como close pueden lanzar la excepción IOException, en caso de error de lectura o cierre de archivo.
En realidad, podríamos no haber usado un DataInputStream y trabajar en forma más
directa:
import java.io.*; public class Ejemplo10 { public static void main(String args[]) throws FileNotFoundException,IOException { FileInputStream fptr; int n; fptr = new FileInputStream("Ejemplo9.java"); do { n = fptr.read(); if (n!=-1) System.out.print((char)n); } while (n!=-1); fptr.close(); } }
Ya que la clase FileInputStream también dispone de métodos
para leer el archivo. Sólo que son unos pocos métodos que nos permiten leer un entero
por vez o un arreglo de bytes. DataInputStream tiene métodos
para leer los datos de muchas formas distintas, y en general resulta más cómodo.
Ahora sí, vamos a ver cómo nos las arreglamos con las excepciones para que no se nos pare el programa con un mensaje tan poco estético...
En lugar de lanzar las excepciones al intérprete, vamos a procesarlas nosotros
mediante la cláusula catch:
// Archivo: Ejemplo11.java // Compilar con: javac Ejemplo11.java // Ejecutar con: java Ejemplo11 <nombre_archivo> import java.io.*; public class Ejemplo11 { public static void main(String args[]) { FileInputStream fptr; DataInputStream f; String linea = null; try { fptr = new FileInputStream(args[0]); f = new DataInputStream(fptr); do { linea = f.readLine(); if (linea!=null) System.out.println(linea); } while (linea != null); fptr.close(); } catch (FileNotFoundException e) { System.out.println("Hey, ese archivo no existe!\n"); } catch (IOException e) { System.out.println("Error de E/S!\n"); } } }
También hicimos un cambio para elegir el archivo a imprimir desde la línea de comandos, en lugar de entrarlo fijo, utilizando para eso el argumento del método main(arg[]), que consiste en una lista de Strings con los parámetros que se pasan en la línea a continuación de java nombre_programa. Por ejemplo, si llamamos a este programa con:
java Ejemplo11 archi.txt otro.xxx
arg[0] contendrá "archi.txt", arg[1] contendrá "otro.xxx", y así sucesivamente.
Por supuesto, si llamamos a Ejemplo11 sin parámetros se lanzará otra excepción al intentar accederlo:
C:\java\curso>java Ejemplo11 java.lang.ArrayIndexOutOfBoundsException: 0 at Ejemplo11.main(Ejemplo11.java:10)
Pero también podríamos capturarla!
Veamos un poquito cómo es esto de capturar excepciones.
La cláusula try engloba una parte del programa donde se pueden lanzar excepciones. Si una excepción se produce, Java busca una instrucción catch (nombre_de_la_excepción variable), y, si la encuentra, ejecuta lo que ésta engloba. Si no encuentra un catch para esa excepción, para el programa y muestra el error que se produjo.
Por ejemplo, para evitar este último error bastaría con agregar:
catch (ArrayIndexOutOfBoundsException e) { System.out.println("Debe ingresar un nombre de archivo!"); System.out.println("Ej.: java Ejemplo11 pepe.txt"); }
Hay que notar que cuando se lanza una excepción el programa igual se detiene, porque
el código que sigue al lanzamiento de la excepción no se ejecuta. Veremos luego cómo se
comporta esto en un objeto que fue creado por otro, y cómo usar la instrucción finally para poner una parte de código que se ejecute pase lo que
pase.
Veamos cómo se comporta esta aplicación si la modificamos para usarla como applet.
/* // ----- Archivo: Ejemplo12.java */ import java.io.*; import java.awt.*; import java.applet.*; public class Ejemplo12 extends Applet { public void init() { new Ventana12(); } } /* // -------- Esta clase es la que en realidad hace el trabajo */ class Ventana12 extends Frame { TextArea contenido; Button cerrar; Ventana12() { super("Ejemplo de E/S"); contenido = new TextArea(); cerrar = new Button("Cerrar"); CargarArchivo(); add("North",contenido); add("South",cerrar); pack(); show(); } public boolean handleEvent(Event e) { if ((e.id==Event.WINDOW_DESTROY)||(e.target==cerrar)) dispose(); return super.handleEvent(e); } void CargarArchivo() { FileInputStream fptr; DataInputStream f; String linea = null; try { fptr = new FileInputStream("Ejemplo12.java"); f = new DataInputStream(fptr); do { linea = f.readLine(); if (linea!=null) contenido.appendText(linea+"\n"); } while (linea != null); fptr.close(); } catch (FileNotFoundException e) { contenido.appendText("Hey, ese archivo no existe!\n"); } catch (IOException e) { contenido.appendText("Error de E/S!\n"); } } }
Lo cargamos desde la página Ejemplo12.html:
<HTML> <HEAD> <TITLE>Ejemplo 12 - Ejemplo con archivo</TITLE> </HEAD> <BODY> <applet code="Ejemplo12.class" width=170 height=150> </applet> </BODY> </HTML>
Mientras corramos esto en la misma máquina, no hay problema (anda muy bien!). Pero qué pasa si intentamos cargarlo desde la red? Para los que no tengan server html puse una copia en:
http://www.amarillas.com/rock/java/Ejemplo12.htm
El archivo no aparece! En su lugar se produce una excepción; en la línea de estado del Microsoft Internet Explorer, por ejemplo, se lee:
exception: com.ms.applet.AppletSecurityException: security.file.read: Ejemplo12.java
Esto es debido a una restricción de seguridad de Java: NO SE PUEDEN CARGAR ARCHIVOS
QUE ESTEN EN UNA MAQUINA DISTINTA A AQUELLA DESDE LA CUAL SE CARGO EL APPLET. El applet se
corre en el cliente, e intenta acceder a un archivo local. Eso es lo que provoca la
excepción (que, por supuesto, puede detectarse con un catch y
tratarse...)
Por cuestiones de seguridad, los applets son más limitados que las aplicaciones Java locales. Las políticas de seguridad las manejan los browsers (no Java), y generalmente los límites que se imponen a los applets son:
Un applet no puede cargar bibliotecas (libraries) ni definir métodos nativos | |
No puede leer o escribir normalmente archivos en el cliente que lo carga desde otro server | |
No puede establecer conexiones de red, salvo al servidor del que proviene | |
No puede arrancar programas en la máquina donde se está ejecutando | |
No puede leer ciertas propiedades del sistema | |
En las ventanas de los applets se indica que se trata de un applet |
Sin embargo, pueden:
Reproducir sonidos | |
Pueden establecer conexiones con el servidor del que provienen | |
Pueden llamar fácilmente páginas HTML desde el browser | |
Pueden invocar métodos públicos de otros applets de la misma página | |
Si se cargan desde la propia máquina (localmente) no tienen ninguna de las restricciones anteriores | |
Pueden seguir corriendo aunque se cambie de página en el browser |
En realidad, la especificación de Java permite que los applets lean archivos en otras
máquinas dando la URL completa; sin embargo, los browsers no lo permiten. Veremos más
adelante cómo intercambiar datos entre máquinas para poder ver un archivo del server,
por ejemplo.
Para terminar este capítulo, el siguiente applet nos permite cargar, editar y grabar archivos ascii a elección. Podemos usar inclusive las acciones "cut & paste" del windows manager (Ctrl-C y Ctrl-V en Windows)!
Cargarlo con "appletviewer Ejemplo13" luego de haberlo compilado (o usar una página html desde un browser):
/* // ----- Archivo: Ejemplo13.java */ import java.io.*; import java.awt.*; import java.applet.*; public class Ejemplo13 extends Applet { public void init() { new Ventana13(); } } /* // -------- Esta clase es la que en realidad hace el trabajo */ class Ventana13 extends Frame { TextArea contenido; Botones13 pieVentana; Ventana13() { super("Ejemplo de E/S"); contenido = new TextArea(); pieVentana = new Botones13(); add("North",contenido); add("South",pieVentana); pack(); show(); } public boolean handleEvent(Event e) { if ((e.id==Event.WINDOW_DESTROY)||(e.id==2003)) dispose(); if (e.id==2001) CargarArchivo(pieVentana.toString()); if (e.id==2002) GrabarArchivo(pieVentana.toString()); return super.handleEvent(e); } void CargarArchivo(String nombre) { FileInputStream fptr; DataInputStream f; String linea = null; contenido.setText(""); try { fptr = new FileInputStream(nombre); f = new DataInputStream(fptr); do { linea = f.readLine(); if (linea!=null) contenido.appendText(linea+"\n"); } while (linea != null); fptr.close(); } catch (FileNotFoundException e) { new Error13("El archivo no existe!"); } catch (IOException e) { new Error13("Error leyendo archivo!"); } } void GrabarArchivo(String nombre) { FileOutputStream fptr; DataOutputStream f; try { fptr = new FileOutputStream(nombre); f = new DataOutputStream(fptr); f.writeBytes(contenido.getText()); fptr.close(); } catch (IOException e) { new Error13("Error grabando archivo!"); } } } /* // -------- Esta es para los botones y el nombre del archivo */ class Botones13 extends Panel { TextField fname; Button cargar; Button grabar; Button cerrar; Botones13() { setLayout(new GridLayout(1,4)); fname = new TextField(); cargar = new Button("Cargar"); grabar = new Button("Grabar"); cerrar = new Button("Cerrar"); add(new Label("Archivo:")); add(fname); add(cargar); add(grabar); add(cerrar); } public boolean handleEvent(Event e) { if ((e.id==Event.ACTION_EVENT)&&(e.target==cargar)) e.id=2001; if ((e.id==Event.ACTION_EVENT)&&(e.target==grabar)) e.id=2002; if ((e.id==Event.ACTION_EVENT)&&(e.target==cerrar)) e.id=2003; return super.handleEvent(e); } public String toString() { return fname.getText(); } } /* // ------- Para mostrar los errores... */ class Error13 extends Frame { Error13(String error) { add("Center",new Label(error)); add("South", new Button("Ok")); pack(); show(); } public boolean handleEvent(Event e) { dispose(); return super.handleEvent(e); } }
Un poco largo... pero vale la pena, ¿no?!
<> Página de tutoriales <> Página Anterior <> Siguiente Capitulo <>