Ficheros Binarios en Java


Un fichero binario o de datos está formado por secuencias de bytes. Estos archivos pueden contener datos de tipo básico (int, float, char, etc) y objetos.
Para poder leer el contenido de un fichero binario debemos conocer la estructura interna del fichero, es decir, debemos saber cómo se han escrito: si hay enteros, long, etc. y en qué orden están escritos en el fichero. Si no se conoce su estructura podemos leerlo byte a byte

ESCRIBIR DATOS EN FICHEROS BINARIOS
Para escribir datos en un fichero binario utilizaremos las clases Java FileOutputStream y DataOutputStream derivadas de OutputStream.
FileOutputStream
La clase FileOutputStream permite tener acceso al fichero para escribir bytes.
Para crear objetos FileOutputStream podemos utilizar los constructores:

FileOutputStream (String ruta)
FileOutputStream (File objetoFile);
FileOutputStream (String ruta, boolean append)
FileOutputStream (File objetoFile, boolean append)
Si el parámetro append es true significa que los datos se van a añadir a los existentes.
Si es false los datos existentes se pierden. Si se utiliza uno de los dos primeros constructores los datos existentes se pierden.
Los constructores lanzan una excepción FileNotFoundException si no existe y no se ha podido crear el fichero.
La clase FileOutputStream proporciona el método write() para escribir bytes en el fichero. Este método lanza una IOException.
DataOutputStream
A partir de un objeto FileOutputStream se puede crear un objeto DataOutputStream, que proporciona métodos para escribir datos de tipo primitivo en el fichero.
Para crear un objeto DataOutputStream se utiliza el constructor:
DataOutputStream(OutputStream nombre);
La clase proporciona métodos writeXxx() donde Xxx es el nombre del tipo primitivo. Lanzan una IOException

EJEMPLOS JAVA DE ESCRITURA EN FICHEROS BINARIOS
Ejemplo 1:
Programa que lee enteros por teclado y los escribe en el fichero datos.dat. La lectura de datos acaba cuando se introduce -1.

import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner;

public class Binarios1 {
   
public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        FileOutputStream fos = null;
        DataOutputStream salida = null;
        int n;

       
try {
            fos = new FileOutputStream("/ficheros/datos.dat");
            salida = new DataOutputStream(fos);

            System.out.print("Introduce número entero. -1 para acabar: ");
            n = sc.nextInt();
            while (n != -1) {
                salida.writeInt(n); //se escribe el número entero en el fichero
                System.out.print("Introduce número entero. -1 para acabar: ");
                n = sc.nextInt();
            }
        } catch (FileNotFoundException e) {
            System.out.println(e.getMessage());
        } catch (IOException e) {
            System.out.println(e.getMessage());
        } finally {
            try {
                if (fos != null) {
                    fos.close();
                }
                if (salida != null) {
                    salida.close();
                }
            } catch (IOException e) {
                System.out.println(e.getMessage());
            }
        }
    }
}

Ejemplo 2:
Programa Java que crea una matriz de elementos de tipo double y lee por teclado el valor de sus elementos. A continuación escribe el contenido de la matriz en un fichero. Al principio del fichero se escriben dos enteros con los valores del número de filas y columnas de la matriz.

import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner;

public class Binarios2 {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);

        FileOutputStream fos = null;
        DataOutputStream salida = null;

        double[][] matriz;
        int filas, columnas, i, j;
        do{
            System.out.print("Número de filas: ");
            filas = sc.nextInt();
        }while(filas<=0);
        do{
            System.out.print("Número de columnas: ");
            columnas = sc.nextInt();
        }while(columnas<=0);

        matriz = new double[filas][columnas]; //se crea la matriz
       
        for (i = 0; i < filas; i++) {     //lectura de datos por teclado
            for (j = 0; j < columnas; j++) {
                System.out.print("matriz[" + i + "][" + j + "]: ");
                matriz[i][j] = sc.nextDouble();
            }
        }
        try {
            //crear el fichero de salida
            fos = new FileOutputStream("/ficheros/matriz.dat");
            salida = new DataOutputStream(fos);

            //escribir el número de filas y columnas en el fichero
            salida.writeInt(filas);
            salida.writeInt(columnas);
           
           //escribir la matriz en el fichero
            for (i = 0; i < filas; i++) {
                for (j = 0; j < columnas; j++) {
                    salida.writeDouble(matriz[i][j]);
                }
            }
        } catch (FileNotFoundException e) {
            System.out.println(e.getMessage());
        } catch (IOException e) {
            System.out.println(e.getMessage());
        } finally {
            try {
                if (fos != null) {
                    fos.close();
                }
                if (salida != null) {
                    salida.close();
                }
            } catch (IOException e) {
                System.out.println(e.getMessage());
            }
        }
    }
}

LECTURA DE FICHEROS BINARIOS
Para leer de un fichero binario utilizaremos las clases Java FileInputStream y DataInputStream derivadas de InputStream.
FileInputStream
La clase FileInputStream permite leer bytes de un fichero.
Para crear objetos FileInputStream podemos utilizar los constructores:

FileInputStream (String ruta)
FileInputStream (File objetoFile);
Ambos lanzan una excepción FileNotFoundException si el fichero no existe.
La clase proporciona el método read() para leer bytes del fichero.
El método read lanza una excepción IOException.
DataInputStream
A partir de un objeto FileInputStream podemos crear un objeto DataInputStream para leer datos de tipo primitivo.
Para crear un objeto DataInputStream se utiliza el constructor:
DataInputStream (InputStream nombre);
La clase proporciona métodos readXxx() donde Xxx es el nombre del tipo primitivo. Lanzan una excepción IOException.
Cuando un método readXxx() alcanza el final del fichero lanza una excepción EOFException.

EJEMPLOS JAVA DE LECTURA DE FICHEROS BINARIOS
Ejemplo 3:
Programa que lee el contenido del fichero creado en el Ejemplo 1. Utilizaremos un bucle infinito para leer los datos. Cuando se llega al final del fichero se lanza la excepción EOFException que se utiliza para salir del bucle while.
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class Binarios3 {
    public static void main(String[] args) {
        FileInputStream fis = null;
        DataInputStream entrada = null;
        int n;
        try {
            fis = new FileInputStream("/ficheros/datos.dat");
            entrada = new DataInputStream(fis);
            while (true) {   
                n = entrada.readInt();  //se lee  un entero del fichero
                System.out.println(n);  //se muestra en pantalla
            }
        } catch (FileNotFoundException e) {
            System.out.println(e.getMessage());
        } catch (EOFException e) {
            System.out.println("Fin de fichero");
        } catch (IOException e) {
            System.out.println(e.getMessage());
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
                if (entrada != null) {
                    entrada.close();
                }
            } catch (IOException e) {
                System.out.println(e.getMessage());
            }
        }
    }
}

Ejemplo 4:
Programa Java que lee el contenido del fichero creado en el Ejemplo 2 y lo muestra por pantalla.

import java.io.DataInputStream;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class Binarios4 {
    public static void main(String[] args) {
        FileInputStream fis = null;
        DataInputStream entrada = null;
        int filas, columnas, i, j;
        try {
            fis = new FileInputStream("/ficheros/matriz.dat");
            entrada = new DataInputStream(fis);
            filas = entrada.readInt();  //se lee el primer entero del fichero
            columnas = entrada.readInt();//se lee el segundo entero del fichero
            for (i = 0; i < filas; i++) {
                for (j = 0; j < columnas; j++) {  // se leen los double y se muestran por pantalla
                    System.out.printf("%8.2f", entrada.readDouble());
                }
                System.out.println();
            }
        } catch (FileNotFoundException e) {
            System.out.println(e.getMessage());
        } catch (EOFException e) {
            System.out.println("Fin de fichero");
        } catch (IOException e) {
            System.out.println(e.getMessage());
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
                if (entrada != null) {
                    entrada.close();
                }
            } catch (IOException e) {
                System.out.println(e.getMessage());
            }
        }
    }
}

7 comentarios:

  1. Hola muy buenas, hice hace poco un cursillo de JAVA y para no olvidar lo aprendido me estoy ejercitando con estos ejercicios aquí expuestos. He hecho los cuatro de esta página, pero el último me falla? Lo he repasado no no veo diferencias en el código, el problema es que el programa que lee la matriz solo lee ceros, quizás el problema esté en el que los guarda, al ser en un archivo binario no se como comprobarlo.Alguna ayuda ?. Carlos.

    ResponderEliminar
    Respuestas
    1. ajaaa, ya encontré el errorrrrrrr.
      No hice copia y pega, sino que lo escribí a mano y el prg que leía la matriz no leía correctamente, el problema estaba en el prg que grababa la matriz y en concreto cuando se almacena el numero de columnas con la instrucción:
      salida.writeInt(columnas);
      lo puse
      salida.write(columnas);
      y así cuando leo las columnas el dato está corrupto.

      Eliminar
    2. Carlos me alegro de que hayas encontrado y corregido el error. Así da gusto resolver dudas!!

      Eliminar
  2. Saludos a todos. guardo de datos de pacientes en un archivo binario (numero de expediente, dni, apellidos, nombres, telefono, direccion y fotografia del paciente), cuando hago la busqueda a traves del numero de expediente solo me muestra el ultimo paciente ingresado y los anteriores no salen, al parecer al guararlos se sobreescriben, aqui les dejo el codigo de guardar y buscar para que me puedan ayudar,

    private void btcGuardarActionPerformed(java.awt.event.ActionEvent evt) {
    // TODO add your handling code here:
    Object nombreArchivo = archivo;
    System.out.println(nombreArchivo);
    try{
    ObjectOutputStream fileout = new ObjectOutputStream(new FileOutputStream((String) nombreArchivo));
    // ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(fichero,true));
    fileout.writeObject(txtNroExpediente.getText());
    fileout.writeObject(txtDni.getText());
    fileout.writeObject(txtApellidos.getText());
    fileout.writeObject(txtNombres.getText());
    fileout.writeObject(txtDireccion.getText());
    fileout.writeObject(txtTelefono.getText());
    fileout.writeObject(lblFoto.getIcon());
    JOptionPane.showMessageDialog(null, "Los datos del paciente se guardaron corecttamente...");
    if(fileout!=null){
    fileout.close();
    }
    }catch(IOException e){}
    desactivarTextFields();
    btcGuardar.setEnabled(false);
    btcNuevo.setEnabled(true);
    btcBuscar.setEnabled(false);
    }

    private void btcBuscarActionPerformed(java.awt.event.ActionEvent evt) {
    // TODO add your handling code here:
    Object nombreArchivo = archivo;
    try{
    try (ObjectInputStream filein = new ObjectInputStream(new FileInputStream((String) nombreArchivo))){
    Object expediente = filein.readObject();
    Object dni = filein.readObject();
    Object apellidos = filein.readObject();
    Object nombres = filein.readObject();
    Object direccion = filein.readObject();
    Object telefono = filein.readObject();
    Object foto = filein.readObject();
    if (txtNroExpediente.getText().equals(expediente)){
    txtNroExpediente.setText((String) expediente);
    txtDni.setText((String) dni);
    txtApellidos.setText((String) apellidos);
    txtNombres.setText((String) nombres);
    txtDireccion.setText((String) direccion);
    txtTelefono.setText((String) telefono);
    lblFoto.setIcon((Icon) foto);
    }
    if(filein!=null){
    filein.close();
    }
    } catch (ClassNotFoundException ex) {
    Logger.getLogger(JDPacientes.class.getName()).log(Level.SEVERE, null, ex);
    }
    }catch(IOException e){}
    }

    ResponderEliminar
  3. // ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(fichero,true)); Es la forma correcta. Si no pones el true entonces se sobreescribe. atte Ramon

    ResponderEliminar
    Respuestas
    1. Primero, agradecerte por a ver leido y respondido mi problema. agregue lo del true, pero igual sigue reescribiendo, solo cuando el ingreso el ultimo numero de expediente me muestra ese paciente. tienes algun email para enviarte mi proyecto y lo abras y le des una miradita.?

      Eliminar