New 2 Java: Construir una Aplicación: 4.- Leer y Escribir Ficheros y Manejar Excepciones

Queremos leer un fichero en nuestra aplicaci�n, pero primero queremos chequear si puede leerse. Asumiendo que hemos asociado el nombre del fichero con un objeto File llamado f, �c�mo chequeamos si se puede leer el fichero?

Chequeamos si un fichero espec�fico es le�ble llamando al m�todo canRead de la clase File. Como el fichero est� asociado con un objeto File a trav�s de un identificador de referencia f, el siguiente c�digo es correcto:

if (f.canRead()) {
    System.out.println("File can be read.");
}

La clase File tiene muchos m�todos �tiles para chequear el estado o para crear directorios y ficheros. Aprenderemos m�s sobre la clase File m�s adelante. Ahora, empezemos el constructor de la clase NorthPanel.

.�Crear el Constructor

La clase NorthPanel es la plantilla para el objeto que rellena la parte superior del panel Dive Logs, por eso le adjuntamos un constructor. Este panel construye un �rea de texto y lee un fichero, mostrando el texto en el �rea de texto. El constructor construye los componentes GUI, como un �rea de texto con un borde, y llama a un m�todo especial que defineremos m�s adelante para leer texto desde un fichero, mostrando el texto en el �rea designada.

Hasta ahora, en la clase NorthPanel, tenemos el siguiente c�digo:

package divelog;

import java.awt.*;
import javax.swing.*;

public class NorthPanel extends JPanel  { // Opens class

 } // Closes class

Vamos a�adir una sentencia import, declarar variables y crear un �rea de texto.

Sigue estos pasos...
  1. Abre el fichero NorthPanel.java en tu editor de texto.
  2. A�ade la sentencia import en negrita de abajo:
    import java.awt.*;
    import javax.swing.*;
    import java.io.*;
    
  3. A�ade las siguientes variables, despu�s de la declaraci�n de la clase:
    public class NorthPanel extends JPanel  { //opens class
    
        JTextArea instruct; 
        String str;
        //BufferedReader is explained later
        BufferedReader br;   
    
  4. A�ade el siguiente constructor:
        public NorthPanel() { //opens constructor
    
          setBackground(Color.white);
          instruct = new JTextArea(5,60);
          instruct.setLayout(new FlowLayout(FlowLayout.CENTER));
          instruct.setBorder(BorderFactory.createTitledBorder(Detailing Dives "));
          instruct.setLineWrap(true);
          instruct.setWrapStyleWord(true);
          instruct.setEditable(false);
          // Method that is defined later
          readFileIntoTextArea();
          add(instruct);
        } //closes constructor
    
    

Este constructor:

  • Selecciona a blanco el color de fondo de este panel.
  • Inicializa un objeto JTextArea con 5 filas y 60 columnas.
  • Selecciona la distribuci�n del �rea de texto con un controlador FlowLayout inicializando dicha clase.
  • Llama al m�todo setBorder y lo pasa en una llamada al m�todo BorderFactory y al m�todo est�tico creatTitledBorder para crear un borde con el texto "Detailing Dives".
  • Se asegura de que el texto insertado en el �rea de texto rompe las l�neas poniendo los m�todos setLineWrap y setWrapStyleWord a true.
  • Hace que el �rea de texto sea de s�lo lectura llamando al m�todo setEditable con false.
  • Llama a readFileIntoTextArea, un m�todo que definiremos m�s adeltante.
  • A�ade el objeto textArea que acabamos de crear al flowLayout de este panel.

El objeto NorthPanel contiene un objeto textArea, pero el constructor llama a un m�todo que todav�a no se ha definido. El m�todo readFileIntoTextArea hace lo que su nombre sugiere: lee un fichero y pone su contenido en un �rea de texto. Aqu� es donde tiene lugar la Java I/O. Cuando se llama al constructor, crea el �rea de texto, luego llama al m�todo que lee el contenido de un fichero y muestra el texto en el �rea de texto.

Para que podamos entender los pasos del manejo de excepciones y las distintas formas de tratar los problemas, intencionadamente no vamos a crear el fichero a leer en el �rea de texto hasta m�s adelante. Por ahora, vamos a escribir c�digo con la intenci�n de crear una condici�n que nos fuerce a manejar el problema de tres formas diferentes:

  • Imprimir un mensaje de error en la consola.
  • Crear una caja de di�logo desplegable que alerte al usuario del problema.
  • Llamar a un m�todo que cree un fichero en el caso de que �ste no exista.

Aunque antes de hacer esto, debemos entender un poco m�s los streams.

.�La clase Reader

La mayor�a de los streams de datos fluyen en una s�la direcci�n, como sus contrapartidas en el mundo real, los rios. Un stream de datos es o un stream de entrada o un stream de salida, y frecuentemente abrimos dos streams a la vez: uno para lectura y chequeo de validaci�n (entrada) y otro para escritura (salida).

El diagrama de abajo muestra el �rbol de clases que usaremos para leer texto desde un fichero. Reader es una clase abstracta para leer streams de caracteres. Como podemos recordar, las clases abstractas requieren que implementemos, o definamos en detalle, sus m�todos. En este caso, los �nicos m�todos que una subclase debe implementar son read(char[], int, int) y close(). Estos son m�todos �ltiles si queremos que nuestra aplicaci�n lea el fichero. El problema con el m�todo read(char[], int, int) es que s�lo lee un car�cter cada vez. Para leer el contenido de un fichero, necesitamos algo m�s pr�ctico.

Recuerda, una clase hija tiene m�s funcionalidad que su clase padre porque lo hereda todo de su padre y define caracter�sticas adicionales que podr�amos usar. Por eso, bajando por el �rbol podemos encontrar InputStreamReader y BufferedReader.

Cuando construimos un InputStreamReader, las reglas de conversi�n tambi�n se definen para cambiar entre 16-bit Unicode y otras representaciones espec�ficas de la plataforma. Esto es �til cuando se leen o escriben ficheros. Cada llamada a uno de los m�todos InputStreamReader.read podr�a hacer que se leyeran uno o m�s bytes desde el stream de bytes subyacente. Para permitir una conversi�n eficiente de los bytes a caracteres, se podr�an leer m�s bytes de los necesarios para satisfacer la operaci�n de lectura actual. De nuevo, s�lo se lee un caracter cada vez.

FileReader es una clase de conveniencia para leer ficheros de caracteres. El constructor de esta clase asume que la codificaci�n de caracteres por defecto y el tama�o del buffer de bytes por defecto son apropiados. Es una clase �til, pero no proporciona m�todos adicionales. Al usar esta clase, descendemos de InputStreamReader, lo que es bueno, pero todav�a necesitamos mejores funcionalidades de lectura.

Observa la clase BufferedReader de la imagen de arriba. Esta clase lee texto desde un stream de entrada de caracteres, almacenando los caracteres proporciona una forma eficiente de lectura de caracteres, arrays y l�neas. Podr�a especificarse el tama�o del buffer o podr�a utilizarse el tama�o por defecto. El tama�o por defecto es suficiente para la mayor�a de los prop�sitos. En otras palabras, un BufferedReader mejora el rendimiento de un objeto Reader asociado proporcionando un buffer de almacenamiento temporal. Reduciendo el n�mero de veces que se debe acceder al disco o a la red.

Ahora nuestra aplicaci�n puede obtener alguna funcionalidad de lectura realmente buena. Esta clase incluso tiene un m�todo readLine para leer una l�nea de texto a la vez. Sin embargo, BufferedReader no puede usarse por s� mismo. En su lugar, debemos envolver o encadenar un Reader dentro de un BufferedReader. Esto se hace pasando un objeto Reader al constructor de BufferedReader.

Por ejemplo:

 BufferedReader in = new BufferedReader(new FileReader("TextFile.txt"));

Si creamos o copiamos este fichero de texto llamado example.txt, y ejecutamos la aplicaci�n ReadMyFile:

  • Creamos un objeto String para contener todo el texto a leer.
  • Encerramos el c�digo en sentencias try y catch para manejo de excepciones.
  • Envolvemos un objeto FileReader dentro de un objeto BufferedReader.
  • Usamos un bucle while y el m�todo readLine para iterar sobre el texto e imprimirlo en la consola.
  • Cerramos el stream cuando no haya m�s l�neas de texto para leer.

.�Leer el Fichero dentro del TextArea

Para leer desde un fichero, conectamos con un stream de entrada y leemos desde �l, usando una variable para contener el texto. Para hacer algo con el texto, vamos al m�todo readFileIntoTextArea de la clase NorthPanel.

Sigue estos pasos...
  1. Abre el fichero NorthPanel.java en tu editor de texto.
  2. Despu�s del corchete de cierre del constructor, a�ade la siguiente declaraci�n de m�todo:
    { // Closes constructor
    
    private void readFileIntoTextArea()   { // opens method
    
  3. Empieza una sentencia try con un corchete abierto y una asociaci�n del fichero que queremos leer con un objeto File:
     try  { //opens try
              
        File f = new File("divedetails.txt");
    
  4. Envuelve un ejemplar del objeto FileReader en un ejemplar de un objeto BufferedReader:
    br = new BufferedReader (new FileReader(f));
  5. Itera sobre cada l�nea usando una construcci�n while con el m�todo readLine, y asignalo a la variable str que creamos anteriormente:
        while ((str = br.readLine()) != null) {//opens while
  6. Pasa el texto del fichero al �rea de texto con el m�todo append de la clase JTextArea. Recuerda que creamos esta variable antes, instruct:
            instruct.append(str);
  7. Cierra el bucle while:
        } //closes while 
  8. cierra la sentencia try:
    } // close try

Aqu� hay un ejemplo de c�mo deber�a estar tu clases hasta ahora.

Recuerda que toda sentencia try necesita un bloque catch, y hasta ahora hemos escrito c�digo para leer un fichero que no existe. Esto intencionadamente crea un error o un condici�n de excepci�n, escribe el c�digo del bloque catch que maneja la condici�n.

La mejor forma de manejar la condici�n es:
  A   Llamar a System.exit(1);
  B.   Usar System.out.println(ioe); para imprimir un mensaje de error en la consola.
  C   Imprimir un mensaje de error en la consola y proporcionar un mensaje desplegable para el usuario.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP
ARTÍCULO ANTERIOR

SIGUIENTE ARTÍCULO