Gracias a la ayuda y los buenos consejos recibidos no solo he aprendido un montón si no que además me han puesto una buena nota

Inicialmente empecé trabajando con un fichero de texto plano, pero me pareció un sistema muy farragoso y opté por trabajar con objetos directamente.
Pego el enlace al post original y los códigos del programa por si a alguien le valen de algo.
Muchas gracias.
http://foro.elhacker.net/java/ayuda_con_un_ejercicio_grabar_datos_en_un_fichero_secuencial_de_texto-t410283.0.html
Clase Principal:
Código:
public class Tarea6_3 implements java.io.Serializable {
//Se implementa la interfaz serializable para que el objeto Cliente pueda
//escribir todos sus datos en fichero.
/**
* @param args the command line arguments
* @throws java.lang.Exception
*/
public static void main(String[] args) throws Exception {
/**
* Menú
* Presenta el menú de operaciones con todas las opciones disponibles
*/
int opcion = 0;
do{
try{
opcion = Integer.parseInt(Menu()); // Mostramos el menu
}
catch (NumberFormatException nfe){
System.out.println(nfe.getMessage());
opcion = 10;
}
switch (opcion){
case 0://Salir del menú
break;
case 1: //Añadir cliente
//Creamos un nuevo objeto cliente de la clase Clientes
Clientes cliente = new Clientes(Clientes.setNombre(),
Clientes.setNif(),
Clientes.setTlf(),
Clientes.setDireccion(),
Clientes.setDeuda());
//Llamada al método guardarEnArchivo.
Archivo.guardarClienteEnArchivo("clientes.dat", cliente);
break;
case 2: //Listar clientes
Archivo.listarClientes();
break;
case 3: //Buscar clientes.
Archivo.buscarCliente();
break;
case 4://Borrar cliente
Archivo.borrarCliente();
break;
case 5://Borrar fichero de clientes. Ojo que no hay vuelta atrás.
Archivo.borrarClientesDat();
break;
default:
System.out.println("Introduzca un valor entre 0 y 6");
}
}while (opcion !=0);
}
/**
* menu()
* Menú de selección. Presenta el menú de opciones
* @return opcion
*/
public static String Menu() {
System.out.println("Men\u00fa");
System.out.println("-------------------------------");
System.out.println("1 - A\u00f1adir cliente");
System.out.println("2 - Listar clientes");
System.out.println("3 - Buscar cliente");
System.out.println("4 - Borrar cliente");
System.out.println("5 - Borrar fichero clientes.dat");
System.out.println("0 - Salir");
System.out.println("-------------------------------");
String opcion = Archivo.sc.next();
return opcion;
}
}
Clase Archivo.
Código:
package tarea6_3;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Recoge todos los métodos necesarios para manipular el archivo clientes.dat
* @author adec29
*/
public class Archivo implements java.io.Serializable {
//Inicializo los miembros de clase.
private static FileOutputStream fos;
private static ObjectOutputStream salida;
private static FileInputStream fis;
private static ObjectInputStream entrada;
final static String temporal = "temporal.dat";
final static String archivo = "clientes.dat";
static Scanner sc=new Scanner(System.in); //Para leer de teclado
static boolean check;// para hacer comprobaciones
/**
* Comprueba si clientes.dat tiene registros
* @return check
*/
private static boolean tieneRegistros(){
//Inicialmente presuponemos que no tenemos registros en clientes.dat
check = false ;
Clientes cliente = null ;
try {
//Abrimos el archivo para lectur.
fis = new FileInputStream(archivo);
entrada = new ObjectInputStream(fis);
// Lee el primer objeto del fichero
cliente = (Clientes) entrada.readObject();
//Hacemos la comprobación.
if (cliente != null){ //Si el objeto cliente tiene algo.
check = true ; //tieneRegistros() devuelve true
}
} catch (FileNotFoundException e) {
System.out.println( "Fichero no encontrado en tieneRegistros()"+e ) ;
} catch (IOException | ClassNotFoundException ex) {
System.out.println( "Capturada excepción en tieneRegistros()"+ex ) ;
}
return(check) ;
}
/**
* Lee los clientes de clientes.dat
* @throws java.io.IOException
*/
public static void listarClientes () throws IOException {
//Preparamos un objeto de la clase Cliente para poder mostrar su
//contenido cuando leamos.
Clientes cliente = null;
try {
//Como vamos a listar solamente, no vamos a modificar nada, abrimos
//clientes.dat en modo lectura.
fis = new FileInputStream(archivo);
entrada = new ObjectInputStream(fis);
//Comprobamos que hay algo en el flujo de datos fis
if (fis != null){
do{
//Leemos el primer objeto cliente a través del buffer "entrada"
//que antes vinculamos al flujo de datos "fis" que lee el
//archivo clientes.dat
cliente = (Clientes) entrada.readObject();
System.out.println(
cliente.getNombre()+" "
+cliente.getNif()+" "
+cliente.getDireccion()+" "
+cliente.getTlf()+" "
+cliente.getDeuda());
//Pero esto sólo lee el primer cliente, si queremos leerlos
//todos habrá que repetir hasta llegar al último.
}while (cliente != null);
} //Cerramos el archivo.
fis.close();
entrada.close();
} catch (EOFException eof) {
System.out.println("¡Fin del fichero!");
} catch (ClassNotFoundException ex) {
Logger.getLogger(Archivo.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* Nos posibilita la escritura de un nuevo registro en clientes.dat
* @param archivo
* @param cliente
*/
public static void guardarClienteEnArchivo(String archivo,
Clientes cliente) {
try {
//Creamos un fujo de salida hacia clientes.dat
fos = new FileOutputStream(archivo, true);
if (tieneRegistros() == true){
//Si clientes.dat YA tiene registros.
//El fujo ObjectOutputStream es el que procesa los datos de
//salida y se ha de vincular a un objeto de la clase
//FileOutputStream.(Serializar)
salida = new MiObjectOutputStream (fos);
////////////////////////////////////////////////////////////////
// ¿Por qué usamos MiObjectOutputStream? //
// Visita esta página. Muy bien explicado.
// http://www.chuidiang.com/java/ficheros/ObjetosFichero.php //
////////////////////////////////////////////////////////////////
}
else {
//Si no tiene registros uso la clase ObjectOutputStream para
//escribir la cabecera y el PRIMER registro
salida = new ObjectOutputStream (fos);
}
//Grabar cliente
if (fos != null) {salida.writeObject(cliente);}
//Cerrar archivo.
fos.close();
salida.close();
//Captura de excepciones.
} catch (IOException ex) {
System.out.println("Excepción capturada en guardarClienteEnArchivo"
+ex.getMessage());
}
}
/**
* Nos permite buscar un cliente a través de su dni
* @throws IOException
* @throws ClassNotFoundException
*/
public static void buscarCliente() throws IOException,
ClassNotFoundException {
//Preparamos un objeto de la clase Cliente para poder mostrar su
//contenido cuando leamos.
Clientes cliente = null;
//Preguntamos por el nif a buscar.
String buscado = Clientes.setNif();
try {
//Como vamos a buscar solamente, no vamos a modificar nada, abrimos
//clientes.dat en modo lectura.
fis = new FileInputStream(archivo);
entrada = new ObjectInputStream(fis);
//Comprobamos que hay algo en el flujo de datos fis
if (fis != null){
do{
//Leemos el primer objeto cliente a través del buffer "entrada"
//que antes vinculamos al flujo de datos "fis" que lee el
//archivo clientes.dat
cliente = (Clientes) entrada.readObject();
//Preguntamos por el cliente a buscar.
String encontrado = cliente.getNif();
//Comparamos buscado y encontrado
if (buscado.equals(encontrado)){
System.out.println("Encontrado cliente."+
"\nNombre: "+cliente.getNombre()+
"\nNif: "+cliente.getNif()+
"\nDirección: "+cliente.getDireccion()+
"\nTlf: "+cliente.getTlf()+
"\nDeuda: "+cliente.getDeuda());
}
//Pero esto sólo lee el primer cliente, si queremos leerlos
//todos habrá que repetir hasta llegar al último.
}while (cliente != null);
//Cerramos Archivo
fis.close();
entrada.close();
}
} catch (EOFException eof) {
//No hagas nada
} catch (ClassNotFoundException ex) {
System.out.println(ex.getMessage());
}
//Informamos del fin de la búsqueda
System.out.println("Búsqueda finalizada.");
}
/**
* Borra un cliente que buscamos a través de su nif tantas veces como lo
* encuentre dentro del fichero clientes.dat
* Para ello creamos un fichero temporal.dat que guarda los clientes
* que vamos leyendo excepto aquellos cuyo nif coincida con el buscaco.
* Posteriormente renombramos clientes.dat a clientes.bak y renombramos
* temporal.dat a clientes.dat.
* Después borramos temporal.dat
* @throws IOException
* @throws ClassNotFoundException
*/
public static void borrarCliente() throws IOException,
ClassNotFoundException {
//Preparamos un objeto de la clase Cliente para poder comparar su
//contenido cuando leamos.
Clientes cliente = null;
//Preguntamos por el nif del cliente a borrar.
String buscado = Clientes.setNif();
try {
//Vamos a buscar. Abrimos clientes.dat en modo LECTURA
fis = new FileInputStream(archivo);
entrada = new ObjectInputStream(fis);
//Comprobamos que hay algo en el flujo de datos fis
if (fis != null){
do{
//Leemos el primer objeto cliente a través del buffer "entrada"
//que antes vinculamos al flujo de datos "fis" que lee el
//archivo clientes.dat
cliente = (Clientes) entrada.readObject();
//Preguntamos por el nif del objeto cliente leido.
String encontrado = cliente.getNif();
//Comparamos buscado y encontrado
if (buscado.equals(encontrado)){
System.out.println("Eliminado cliente."+
"\nNombre: "+cliente.getNombre()+
"\nNif: "+cliente.getNif()+
"\nDirección: "+cliente.getDireccion()+
"\nTlf: "+cliente.getTlf()+
"\nDeuda: "+cliente.getDeuda());
}else {
Temporal.guardarClienteEnArchivoTemporal(temporal, cliente);
}
//Pero esto sólo lee el primer cliente, si queremos leerlos
//todos habrá que repetir hasta llegar al último.
}while (cliente != null);
//Cerramos archivo.
fis.close();
entrada.close();;
}
} catch (EOFException eof) {
//No hagas nada
} catch (ClassNotFoundException ex) {
System.out.println(ex.getMessage());
}
//Informamos del fin de la búsqueda
System.out.println("Búsqueda finalizada.");
//Renombramos, copiamos y borramos.
//Creamos tres abstracciones usando la clase File
File clientesDat = new File ("clientes.dat");
File clientesBak = new File ("clientes.bak");
File temp = new File ("temporal.dat");
try {
//Renombramos y comprobamos.
check = clientesDat.renameTo(clientesBak);
if (check) {
System.out.println("clientes.dat renombrado a clientes.bak");
} else {
System.out.println("El renombrado no se ha podido realizar");
}
//Renombramos y comprobamos.
check = temp.renameTo(clientesDat);
if (check) {
System.out.println("temporal.dat renombrado a clientes.dat");
} else {
System.out.println("El renombrado no se ha podido realizar");
}
//Borramos los clientes.bak que ya no lo necesitamos.
check = clientesBak.delete();
if (check) {
System.out.println("clientes.bak borrado");
} else {
System.out.println("El borrado no se ha podido realizar");
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
/**
* Borra el archivo clientes.dat
*/
public static void borrarClientesDat(){
//Instanciamos clientesDat la clase File y le pasamos el nombre del
//fichero con el que vamos a trabajar
File clientesDat = new File ("clientes.dat");
//Para borrar el fichero deberemos de invocar el método .delete()
//de la clase File. En caso de que se pueda realizar el borrado del
//fichero, dicho método devolverá true.
//En caso contrario devolverá false.
try {
if (clientesDat.delete())//true
{
System.out.println("Fichero borrado con éxito");
} else //false
{
System.out.println("No se ha podido borrar el fichero");
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
Clase Cliente:
Código:
import java.util.Scanner;
/**
*
* @author adec29
*/
public class Clientes implements java.io.Serializable {
//Inicializo los miembros de clase.
static Scanner teclado=new Scanner(System.in); //Para leer de teclado
static boolean check;// Para hacer comprobaciones
//Inicializo atributos de clase
private String nif; //Nif del cliente
private String nombre; //Nombre del cliente
private String telefono; // Teléfono del cliente
private String direccion; // Dirección del cliente
private String deuda; //Deuda del dliente
/**
* Constructor de la clase
* Los datos son comprobados dentro del método que los crea
* @param nombre
* @param nif
* @param telefono
* @param direccion
* @param deuda
* @throws Exception
*/
public Clientes(String nombre, String nif, String telefono,
String direccion, String deuda) throws Exception {
Archivo.check = false;
this.nombre = nombre;
this.nif = nif;
this.telefono = telefono;
this.direccion = direccion;
this.deuda = deuda;
}
// Métodos set y get
/**
* setNombre()
* @return nombre
* Nos permite establecer el nombre del cliente. Verifica que el nombre
* introducido es correcto siempre y cuando la longitud del String nombre
* se halle entre 3 y 40 caracteres.
*/
public static String setNombre(){
String nombre = "x";
do{
System.out.println("Introduce el nombre del cliente (3-40 caracteres):");
nombre = teclado.nextLine();
if ((nombre.length() < 3) || (nombre.length() > 40))
System.out.println("El nombre debe tener entre 3 y 40 caracteres");
}
while ((nombre.length() < 3) || (nombre.length() > 40));
return nombre;
}
/**
* setNif()
* @return nif
* Nos permite establecer el nif del cliente. Voy a dar por correcto una
* cadena de 9 caracteres
*/
public static String setNif(){
String nif = "x";
do{
System.out.println("Introduce el nif del cliente (9 caracteres):");
nif = teclado.nextLine();
if ((nif.length() < 9) || (nif.length() > 9))
System.out.println("El nif debe tener 9 caracteres");
}
while ((nif.length() < 9) || (nif.length() > 9));
return nif;
}
/**
* setTlf()
* @return tlf
* Nos permite establecer el teléfono del cliente. Voy a dar por correcto una
* cadena de 9 caracteres
*/
public static String setTlf(){
String tlf = "x";
do{
System.out.println("Introduce el teléfono del cliente (9 caracteres):");
tlf = teclado.nextLine();
if ((tlf.length() < 9) || (tlf.length() > 9))
System.out.println("El teléfono debe tener 9 caracteres");
}
while ((tlf.length() < 9) || (tlf.length() > 9));
return tlf;
}
/**
* setDireccion()
* @return dir
* Nos permite establecer la dirección del cliente. Asume que la dirección
* introducida es correcta siempre y cuando la longitud del String dir
* se halle entre 3 y 40 caracteres.
*/
public static String setDireccion(){
String dir = "x";
do{
System.out.println("Introduce la dirección cliente (10-50 caracteres):");
dir = teclado.nextLine();
if ((dir.length() < 3) || (dir.length() > 40))
System.out.println("El nombre debe tener entre 10 y 50 caracteres");
}
while ((dir.length() < 10) || (dir.length() > 50));
return dir;
}
/**
* setDeuda
* Nos permite establecer la cantidad que debe el cliente
* @return deuda
*/
public static String setDeuda() {
String deuda;
System.out.println("Indique la cantidad adeudada por el cliente: ");
deuda = teclado.next();
return deuda;
}
/**
* getNif
* Nos devuelve el nif del cliente
* @return nif
*/
public String getNif() {
return nif;
}
/**
* getNombre
* Nos devuelve el nombre del cliente
* @return nombre
*/
public String getNombre() {
return nombre;
}
/**
* getTlf
* Nos devuelve el teléfono del cliente
* @return teléfono
*/
public String getTlf() {
return telefono;
}
/**
* getDireccion
* Nos devuelve la dirección del cliente
* @return direccion
*/
public String getDireccion() {
return direccion;
}
/**
* getDeuda
* Nos devuelve la deuda que tiene el cliente
* @return deuda
*/
public String getDeuda() {
return deuda;
}
}
Clase temporal:
Código:
public class Temporal implements java.io.Serializable {
private static FileInputStream fistemp;
static final String temporal = "temporal.dat";
private static ObjectInputStream entradatemp;
private static ObjectOutputStream salidatemp;
private static FileOutputStream fostemp;
private static boolean tempcheck;
/**
* Nos posibilita la escritura de un nuevo registro en temporal.dat
* @param temporal
* @param cliente
*/
public static void guardarClienteEnArchivoTemporal(String temporal,
Clientes cliente) {
try {
fostemp = new FileOutputStream(temporal, true);
if (tieneRegistrosTemporal() == true) {
salidatemp = new MiObjectOutputStream(fostemp);
} else {
salidatemp = new ObjectOutputStream(fostemp);
}
if (fostemp != null) {
salidatemp.writeObject(cliente);
}
fostemp.close();
salidatemp.close();
} catch (IOException ex) {
System.out.println("Excepci\u00f3n capturada en "
+ "guardarClienteEnArchivo" + ex.getMessage());
}
}
/**
* Comprueba si temporal.dat tiene registros.
*/
private static boolean tieneRegistrosTemporal() {
tempcheck = false;
Clientes cliente = null;
try {
fistemp = new FileInputStream(temporal);
entradatemp = new ObjectInputStream(fistemp);
cliente = (Clientes) entradatemp.readObject();
if (cliente != null) {
tempcheck = true;
}
} catch (FileNotFoundException e) {
System.out.println("Fichero no encontrado en "
+ "tieneRegistrosTemporal()" + e);
} catch (IOException | ClassNotFoundException ex) {
//no hagas nada
}
return tempcheck;
}
}
Y por último, la solución a todos los problemas que tenía.
cito fuente:
http://www.chuidiang.com/java/ficheros/ObjetosFichero.php
y pego clase:
Código:
public class MiObjectOutputStream extends ObjectOutputStream
{
public MiObjectOutputStream(OutputStream out) throws IOException
{
super(out);
}
protected MiObjectOutputStream() throws IOException, SecurityException
{
super();
}
@Override
protected void writeStreamHeader() throws IOException
{
}
}