Zona HTML Zona Java Zona PHP Zona ASP Zona Bases de datos
-Tutoriales

I/O: Leer y Escibir


Escribir Streams Filtrados

Lo siguiente es una lista de pasos a realizar cuando escribamos nuestro propios streams filtrados tanto de entrada como de salida.

  • Crear una subclase de FilterInputStream y FilterOutputStream. Normalmente los streams de entrada y salida vienen en parejas, por eso necesitamos crear las dos versión del stream filtrado.
  • Sobreescribir los métodos read y write.
  • Sobreescribir cualquier otro método que pudieramos necesitar.
  • Aseguranos de que los streams de entrada y salida funcionan juntos.

Esta sección nos muestra cómo implementar nuestros propios streams filtrados a través de un ejemplo que implementa una pareja de streams filtrados de entrada y salida.

Tanto el stream de entrada como el de salida usan una clase checksum para calcular el checksum de los datos escritos o leídos desde el stream.

El checksum se usa para determinar si los datos leídos por el stream de entrada corresponden con los datos escritos por el stream de salida.

Cuatro clases y un interface componen este programa de ejemplo:

  • Las subclases de los streams de entrada y salida filtrados--CheckedOutputStream y CheckedInputStream.
  • El interface Checksum y la clase Adler32 calculan un checksum para los streams.
  • La clase CheckedIOTest define el método main para el programa.

. La clase CheckedOutputStream

La clase CheckedOutputStream es una subclase de FilterOutputStream que calcula un checksum sobre los datos que están siendo escritos en el stream. Cuando se crea un CheckedOutputStream, debemos usar su único constructor.

public CheckedOutputStream(OutputStream out, Checksum cksum) {
    super(out);
    this.cksum = cksum;
}

Este constructor toma un argumento OutputStream y otro Checksum.

El argumento OutputStream es el stream de salida que este CheckedOutputStream debe filtrar. El argumento Checksum es un objeto que calcula un checksum. CheckedOutputStream se autoinicializa llamando al constructor de su superclase e inicializando una variable privada , cksum, con el objeto Checksum. El CheckedOutputStream usa cksum para actualizar el checksum cada vez que se escribe un dato en el stream.

CheckedOutputStream necesita sobreescribir los métodos write de FilterOutputStream para que cada vez que se llame al método write, se actualice el checksum. FilterOutputStream define tres versiones del método write.

  1. write(int i)
  2. write(byte[] b)
  3. write(byte[] b, int offset, int length)

CheckedOutputStream sobreescribe estos tres métodos.

public void write(int b) throws IOException {
    out.write(b);
    cksum.update(b);
}

public void write(byte[] b) throws IOException {
    out.write(b, 0, b.length);
    cksum.update(b, 0, b.length);
}

public void write(byte[] b, int off, int len) throws IOException {
    out.write(b, off, len);
    cksum.update(b, off, len);
}

Las implementaciones de estos tres métodos write son correctas: escriben los datos en el stream de salida al que este stream está adjuntado, luego actualiza el checksum.

. La Clase CheckedInputStream

La clase CheckedInputStream.

CheckedInputStream es una subclase de FilterInputStream que calcula un checksum de los datos que están siendo leídos desde el stream. Cuando se crea un CheckedInputStream, debemos usar su único constructor:

public CheckedInputStream(InputStream in, Checksum cksum) {
    super(in);
    this.cksum = cksum;
}

Este constructor es similar al de la clase CheckedOutputStream.

Sólo que CheckedOutputStream necesita sobreescribir los métodos write de FilterOutputStream, CheckedInputStream debe sobreescribir los métodos read de FilterInputStream para que cada que vez que se llame al método read, se actualice el checksum. Como con FilterOutputStream, FilterInputStream define tres versiones del método read y CheckedInputStream las sobreescribe todas.

public int read() throws IOException {
    int b = in.read();
    if (b != -1) {
        cksum.update(b);
    }
    return b;
}

public int read(byte[] b) throws IOException {
    int len;
    len = in.read(b, 0, b.length);
    if (len != -1) {
        cksum.update(b, 0, len);
    }
    return len;
}

public int read(byte[] b, int off, int len) throws IOException {
    len = in.read(b, off, len);
    if (len != -1) {
        cksum.update(b, off, len);
    }
    return len;
}

Las implementaciones de estos tres métodos read son correctas: leen los datos desde el stream de entrada al que está adjunto este stream filtrado; entonces si se leyó realmente algún dato, se actualiza el checksum.

. El Interface Checksum y la clase Adler32

El interface Checksum define cuatro métodos para que lo implementen los objetos checksum; estos métodos resetean, actualizan y devuelven el valor del checksum. Podríamos escribir una clase Checksum que calcule un tipo específico de checksum como el CRC-32.

Observa que la herencia en el checksum es la noción de estado. El objeto checksum no sólo calcula un checksum y ya está. En vez de eso, el checksum es actualizado cada vez que se lee o se escribe información en el stream para el que este objeto calcula el checksum. Si queremos reutilizar un objeto checksum, debemos resetearlo.

Para este ejemplo, hemos implementado el checksum Adler32, que es casi una versión del checksum CRC-32 pero puede ser calculado más rápidamente.

. Un Programa de Prueba

La última clase del ejemplo, CheckedIOTest, contiene el método main para el programa.

import java.io.*;

public class CheckedIOTest {
    public static void main(String[] args) throws IOException {

       Adler32 inChecker = new Adler32();
       Adler32 outChecker = new Adler32();
       CheckedInputStream in = null;
       CheckedOutputStream out = null;

       try {
           in = new CheckedInputStream(
			   new FileInputStream("farrago.txt"),
			   inChecker);
           out = new CheckedOutputStream(
			    new FileOutputStream("outagain.txt"),
			    outChecker);
       } catch (FileNotFoundException e) {
           System.err.println("CheckedIOTest: " + e);
           System.exit(-1);
       } catch (IOException e) {
           System.err.println("CheckedIOTest: " + e);
           System.exit(-1);
       }

       int c;

       while ((c = in.read()) != -1)
          out.write(c);

       System.out.println("Input stream check sum: " +
			  inChecker.getValue());
       System.out.println("Output stream check sum: " +
			  outChecker.getValue());

       in.close();
       out.close();
    }
}

El método main crea dos objetos Adler32, uno para un CheckedOutputStream y otro para un CheckedInputStream. El ejemplo requiere dos objetos checksum porque los objetos checksum se actualizan durante las llamadas a lo métodos read y write que ocurren concurrentemente.

Luego, main abre un CheckedInputStream sobre un pequeño fichero de texto, farrago.txt, y un CheckedOutputStream sobre un fichero de salida llamado outagain.txt, que no existe hasta que ejecutemos el programa por primera vez.

El método main lee el texto desde el CheckedInputStream y simplemente lo copia en el CheckedOutputStream. Los métodos read y write usan los objetos Adler32 para calcular un checksum durante la lectura y escritura. Después de haber leído completamente el fichero de entrada (y consecuentemente se haya completado de escribir el fichero de salida), el programa imprime los checksums de los dos streams (que deben ser iguales) y cierra los dos streams.

Cuando ejecutemos CheckedIOTest, deberíamos ver esta salida:

Input stream check sum: 736868089
Output stream check sum: 736868089

. Filtrar Ficheros de Acceso Aleatorio

Todos los streams filtrados de java.io descienden de InputStream o OutputStream, que implementan ficheros de acceso secuencial. Por eso si subclasificamos FilterInputStream o FilterOutputStream nuestros streams filtrados también serán ficheros de acceso secuencial.

Escribir Filtros para Ficheros de Acceso Aleatorio, más adelante en esta lección nos muestra cómo re-escribir este ejemplo para que funcione sobre un RandomAccessFile también como sobre un DataInputStream o un DataOutputStream.

 
Patrocinados
 

Copyright © 1999-2006 Programación en castellano. Todos los derechos reservados.
Formulario de Contacto - Datos legales - Publicidad

Hospedaje web y servidores dedicados linux por Ferca Network