Utilizar DataInputStream y DataOutputStream

Esta página muestra cómo utilizar las clases DataInputStream y DataOutputStream del paquete java.io. Utiliza un ejemplo, DataIOTest, que lee y escribe datos tabulados (facturando productos Java). Los datos tabulados están formateados en columnas, donde cada columna está separada de la siguiente por un Tab. Las columnas contienen los precios de venta, el número de unidades pedidas, y una descripción del producto, de esta forma:
19.99   12      Java T-shirt
9.99    8       Java Mug
DataOutputStream, al igual que otros canales de salida filtrados, debe ser añadido a algún OutputStream. En este caso, se añade a un FileOutputStream que se ha seleccionado para escribir en un fichero llamado invoice1.txt.
DataOutputStream dos = new DataOutputStream(
                           new FileOutputStream("invoice1.txt"));
Luego, DataIOTest utiliza el método especializado writeXXX() de DataOutputStream que escribe los datos de la factura (que están contenidos dentro de arrays en el programa) de acuerdo con el tipo de dato que se está escribiendo:
for (int i = 0; i < prices.length; i ++) {
    dos.writeDouble(prices[i]);
    dos.writeChar('\t');
    dos.writeInt(units[i]);
    dos.writeChar('\t');
    dos.writeChars(descs[i]);
    dos.writeChar('\n');
}
dos.close();
Observa que este código cierra el canal de salida cuando termina.

Luego, DataIOTest abre un DataInputStream con el fichero que acaba de escribir:

DataInputStream dis = new DataInputStream(
                          new FileInputStream("invoice1.txt"));
DataInputStream, también debe ser añadido a algún otro InputStream. En este caso, se ha añadido a un FileInputStream seleccionado para leer el ficheo que se acaba de escribir --invoice1.txt. DataIOTest lee de nuevo los datos utilizando los métodos especializados readXXX() de DataInputStream.
try {
    while (true) {
        price = dis.readDouble();
        dis.readChar();       // Elimina el tab
        unit = dis.readInt();
        dis.readChar();       // Elimina el tab
        desc = dis.readLine();
        System.out.println("Ha pedido " + unit + " unidades de " + desc + " a" + price);
        total = total + unit * price;
    }    
} catch (EOFException e) {
}
System.out.println("Para un TOTAL de: $" + total);
dis.close();
Cuando se han leido todos los datos, DataIOTest muestra una sentencia que sumariza el pedido y cantidad total, y cierra el canal.

Observa el bucle que utiliza DataIOTest para leer los datos desde el DataInputStream. Normalmente, para la lectura verás un bucle como este:

while ((input = dis.readLine()) != null) {
    . . .
}
El método readLine() devuele un valor, null, que indica que se ha alcanzado el final del fichero. Muchos de los métodos readXXX() de DataInputStream no pueden hacer esto porque cualquier valor devuelto para indicar el final del fichero también podría ser interpretado como un valor legitimo leído desde el canal. Por ejemplo, supongamos que has utilizado -1 para indicar el final del fichero. Bien, no puedes hacerlo, porque -1 es un valor legitimo que puede ser leido desde la entrada del canal utilizando readDouble(), readInt(), o cualquiera de los otros métodos que leen números. Entonces los métodos readXXX() de DataInputStream lanzan una EOFExcepcition. Cuando ocurre una EOFException el bucle while(true) termina.

Cuando se ejecute el programa DataIoTest verás la siguiente salida:

Ha pedido 12 unidades de Camiseta Java a $19.99
Ha pedido 8 unidades de Mug Java a $9.99
Ha pedido 13 unidades de Muņechos Duke a $15.99
He pedido 29 unidades de Pin Java a $3.99
Para un TOTAL de: $892.88


Ozito