18 nov 2015

Acceso aleatorio a ficheros en Java

Java dispone de la clase RandomAccessFile que permite acceder al contenido de un fichero binario de forma aleatoria.

Para crear objetos de esta clase, al constructor se le puede pasar, o la ruta mediante un String o mediante un File. En cualquiera de los dos casos hay que pasar un segundo parámetro con el modo de acceso. El modo de acceso puede ser “r”, “rw”

Ejemplos:
Fich= new RandomAccessFile(String nombre, String modoAcceso)
Fich = new RandomAccessFile(File fic, String modoAcceso)


Los métodos más importantes son:
long getFilePointer()
Devuelve la posición del puntero en el fichero.
void seek(long pos)
Pone el puntero en la posición dada por pos, tomada desde el inicio.
long length()
Devuelve el tamaño del fichero en bytes.
Int skipBytes (int desplaz)
Mueve el puntero desde su posición el número de bytes indicado por desplaz.

Ejemplo:
Vamos a guardar los datos de una serie de empleados. Interesa que los datos de cada persona tengan la misma longitud para poder saltar e ir a una persona, para ello limitamos (fijamos) el tamaño de los String antes de escribirlos:

buffer = new StringBuffer(apellidos[i]);
buffer.setLength(10);

El resto de campos tienen una longitud fija, porque son enteros y double.
En total: int (4 bytes), string (20 bytes), int (4 bytes) y double (8 bytes) = 36 bytes.
Tamaño del fichero= 8 registros x 36 bytes = 288 bytes

public class EscribirFichAleatorio {
public static void main(String[] args) throws IOException {
        // TODO code application logic here
        File fich = new File("Empl_aleat.dat");
        RandomAccessFile file = new RandomAccessFile(fich, "rw");
        String[] apellidos = {"MARTÍN", "SORIA", "FERNÁNDEZ", "LUNA", "GARCÍA", "PÉREZ", "RODRÍGUEZ", "MARTÍNEZ"};
        int[] dept = {10, 20, 30, 20, 10, 40, 30, 40};
        Double[] salario = {850.65, 12035.36, 2156.36, 1500.32, 989.23, 1566.32, 1866.88, 2356.78};
        StringBuffer buffer = null;
        for (int i = 0; i < apellidos.length; i++) {
            file.writeInt(i + 1); //identificador de empleado
            buffer = new StringBuffer(apellidos[i]);
            buffer.setLength(10);
            file.writeChars(buffer.toString());
            file.writeInt(dept[i]);
            file.writeDouble(salario[i]);
        }
        file.close();
    }
}


13 nov 2015

Lectura / Escritura de objetos en Java

Con algunas limitaciones, los objetos se pueden leer y escribir en flujos de forma similar a los tipos primitivos. Concretamente, las clases ObjectInputStream y ObjectOutputStream poseen las mismas funcionalidades que DataInputStream y DataOutputStream (y otras específicas de objetos), lo cual da lugar a que un flujo de objetos pueda contener tanto tipos primitivos como objetos.

Los métodos que más interés tienen son
Object readObject()
void writeObject(Object obj)
que leen/escriben el próximo objeto presente en el flujo.


Ejemplo de uso:

package flujosdeobjetos;

import java.io.*;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Locale;
import java.util.TimeZone;

public class FlujosDeObjetos {

    static final String archivoDeDatos = "datosDeFacturacion.bin";
    static final BigDecimal[] precio_unitario = {
        new BigDecimal("19.99"),
        new BigDecimal("9.99"),
        new BigDecimal("15.99"),
        new BigDecimal("3.99"),
        new BigDecimal("4.99")};
    static final int[] num_unidades = {12, 8, 13, 29, 50};
    static final String[] descripciones = {"memoria usb",
        "tarjeta sd",
        "teclado",
        "disco usb",
        "disco duro"};

    public static void main(String[] args)
            throws IOException, ClassNotFoundException {

        TimeZone tz = TimeZone.getTimeZone("Europe/Madrid");
        Locale loc = new Locale("ES");
        Calendar cal = Calendar.getInstance(tz, loc);

        ObjectOutputStream f_sal = null;
        try {
            f_sal = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(archivoDeDatos)));

            f_sal.writeObject(cal);
            for (int i = 0; i < precio_unitario.length; i++) {
                f_sal.writeObject(precio_unitario[i]);
                f_sal.writeInt(num_unidades[i]);
                f_sal.writeUTF(descripciones[i]);
            }
        } finally {
            f_sal.close();
        }

        ObjectInputStream f_ent = null;
        try {
            f_ent = new ObjectInputStream(new BufferedInputStream(new FileInputStream(archivoDeDatos)));

            Calendar fecha = null;
            BigDecimal precio;
            int unidades;
            String descripcion;
            BigDecimal total = new BigDecimal(0);

            fecha = (Calendar) f_ent.readObject();
            System.out.format("Hoy es %tA, %<te de %<tB de %<tY:%n%n", fecha);

            try {
                while (true) {
                    precio = (BigDecimal) f_ent.readObject();
                    unidades = f_ent.readInt();
                    descripcion = f_ent.readUTF();
                    total = total.add(precio.multiply(new BigDecimal(unidades)));
                }
            } catch (EOFException e) {
            }
            System.out.format("%nImporte total: %.2f€%n", total);
        } finally {
            f_ent.close();
        }
    }

}

12 nov 2015

Lectura / Escritura de datos de tipos primitivos en Java

Se utilizan las clases DataInputStream y DataOutputStream. Estas clases, además de los métodos read() y write(), proporcionan métodos específicos para cada tipo de dato primitivo.

Ejemplos:
File fich= new File(ruta);
FileInputStream fis= new FileInputStream(fich);
DataInputStream dis= new DataInputStream(fis);

File fich= new File(ruta);
FileOutputStream fos= new FileOutputStream(fich);
DataOutputStream dos= new DataOutputStream(fos);


Lectura/Escritura de datos de tipos primitivos (buffered)

Se pueden utilizar con memoria intermedia. Por ejemplo:

archivo_salida = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream(ruta)));

archivo_entrada = new DataInputStream(
new BufferedInputStream(
new FileInputStream(ruta)));

donde ruta denota un ejemplar de File o un ejemplar de String.

Ejemplo de uso:

package flujosdedatos;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FlujosDeDatos {
    static final double[] precios = {19.99, 9.99, 15.99, 3.99, 4.99};
    static final int[] numerosDeUnidades = {12, 8, 13, 29, 50};
    static final String[] descripciones = {"memoria usb", "tarjeta sd",         "teclado", "disco usb", "disco duro"};

    public static void main(String[] args) throws IOException {
        DataOutputStream f_sal = null;

        try {
            f_sal = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("facturacion.bin")));

            for (int i = 0; i < precios.length; i++) {
                f_sal.writeDouble(precios[i]);
                f_sal.writeInt(numerosDeUnidades[i]);
                f_sal.writeUTF(descripciones[i]);
            }
        } finally {
            f_sal.close();
        }
       
        DataInputStream f_ent = null;
        double total = 0.0;
        try {
            f_ent = new DataInputStream(new BufferedInputStream(new FileInputStream("facturacion.bin")));

            double precio;
            int numero_de_unidades;
            String descripcion;

            try {
                while (true) {
                    precio = f_ent.readDouble();
                    numero_de_unidades = f_ent.readInt();
                    descripcion = f_ent.readUTF();
                    total += numero_de_unidades * precio;
                }
            } catch (EOFException e) {
            }
            System.out.format("Importe total: %.2f€%n", total);
        } finally {
            f_ent.close();
        }
    }
}


Flujos de datos – DataOutputStream

void flush()
Vuelca en disco la memoria intermedia
int size()
Proporciona el número de bytes escritos hasta el momento.
void write(byte[] b, int ppio, int num)
Escribe num elementos de byte, empezando en ppio.
void write(int b)
Escribe el byte menos significativo del int que se le proporciona como argumento.
void writeBoolean(boolean v)
Escribe un valor boolean en forma de byte
void writeByte(int v)
Escribe el byte menos significativo del int que se le proporciona como argumento.
void writeBytes(String s)
Escribe la cadena en forma de bytes, descartando el byte superior de cada char
void writeChar(int v)
Escribe un char en forma de 2 bytes, con el MSB en primer lugar.
void writeChars(String s)
Escribe la cadena como una sucesión de caracteres (con 2 bytes cada uno).
void writeDouble(double v)
Traduce v a long empleando el método de Double doubleToLongBits, y escribe ese long en forma de 8 bytes con el MSB en primer lugar.
void writeFloat(float v)
Traduce v a int empleando el método de FloatfloatToIntBits y escribe ese int en forma de 4 bytes con el MSB en primer lugar.
void writeInt(int v)
Escribe el int v en forma de 4 bytes, con el MSB en primer lugar.
void writeLong(long v)
Escribe el long v en forma de 8 bytes, con el MSB en primer lugar.
void writeShort(int v)
Escribe el short v en forma de 2 bytes, con el MSB en primer lugar.
void writeUTF(String str)
Escribe los caracteres de la cadena en formato UTF-8 modificado


Flujos de datos – DataInputStream

int read(byte[] b)
Lee bytes hasta llenar b o acabar el fichero. Devuelve el número de bytes leídos, o -1 si el archivo está vacío.
int read(byte[] b, int off, int ppio)
Lee hasta len bytes, almacenándolos a partir de ppio.
boolean readBoolean()
Lee un byte y proporciona false si es 0 o true si no.
byte readByte()
Lee un byte.
char readChar()
Lee 2 bytes y los devuelve en forma de carácter.
double readDouble()
Lee 8 bytes y los devuelve en forma de double.
float readFloat()
Lee 4 bytes y los devuelve en forma de float.
void readFully(byte[] b)
Intenta llenar b de bytes. Si acaba el archivo o hay un error de E/S lanza una EOFException o IOException.
void readFully(byte[] b, int ppio, int num)
Intenta leer num bytes, almacenándolos a partir de ppio.
int readInt()
Inverso de writeInt(), lee 4 bytes y devuelve un int. Supone que el MSB está a la izquierda.
long readLong()
Inverso de writeLong(), lee 8 bytes y devuelve un long. Supone que el MSB está a la izquierda.
short readShort()
Inverso de writeShort(), lee 2 bytes y devuelve un short. Supone que el MSB está a la izquierda.
int readUnsignedByte()
Lee un byte y lo extiende por ceros para dar un int, entre 0 y 255. Inverso de writeByte hasta 255.
int readUnsignedShort()
Lee dos bytes para dar un int, entre 0 y 65535. Inverso de writeShort hasta 65535.
String readUTF()
Lee cadenas escritas con writeUTF.
static String readUTF(DataInput in)
Lee cadenas escritas con writeUTF en el ejemplar de DataInput aportado
int skipBytes(int n)
Intenta saltar n bytes, proporciona el número de bytes que ha saltado. No lanza excepciones.