21 marzo 2006

Mis problemas con ObjectOutputStream

Me he puesto a jugar a escribir y leer ficheros con ObjectOutputStream y me he tropezado con un par de cosas curiosas.

Normalmente, para escribir objetos en un fichero podemos abrir un ObjectOutputStream asi

ObjectOutputStream oos = new ObjectOuputStream (new FileOutputStream("fichero.dat"));

Luego, símplemente vamos escribiendo nuestros objetos

oos.writeObject(unObjecto);

La primera pega que me he encontrado, es que no podemos reutilizar unObjeto (una única instancia de nuestra clase/dato) para escribirlo varias veces. Si hacemos

oss.writeObject(unObjeto);
unObjeto.setAtributo(nuevoValor);
oos.writeObject(unObjeto);

cuando vayamos a leer, leemos el primer objeto dos veces y ni rastro del segundo. Da la impresión de que ObjectOutputStream se guarda los bytes que va serializando, de forma que si mandamos escribir el mismo objeto por segunda vez, se ahorra la serializacion. Sin embargo, no revisa si los datos internos han cambiado.

Para evitar esto, podemos hacer un new por cada objeto que queramos meter

oss.writeObject (unObjeto);
unObjeto=new MiObjeto();
unObjeto.setAtributo(nuevoValor);
oos.writeObject(unObjeto);

o bien podemos usar el métod writeUnshared() en vez de writeObject(). De todas formas, he visto algunos problemas con writeUnshared() si no actualizamos todos los atributos de unObjeto antes de escribirlo por segunda vez. Los atributos que no actualizamos y mantenemos su antiguo valor, luego se escriben con el valor de la primera vez que hayamos metido unDato en el stream.

La otra pega que me he encontrado es que al hacer new ObjectOutputStream(...), esta clase escribe unos bytes de cabecera en el stream. Como new ObjectInputStream(...) lee esa cabecera correctamente, para nosotros es como si no existiera y no hay ningún problema.

El problema se presenta si abrimos el fichero por segunda vez para añadir más datos

ObjectOutputStream oos = new ObjectOuputStream (new FileOutputStream("fichero.dat",true));

Esto volverá a escribir una cabecera justo al final de lo que ya tenemos en el fichero, entre los datos de antes y los que vayamos a insetar ahora.

Cuando leamos con ObjectInputStream, la primera cabecera se lee bien, luego vamos leyendo datos y al llegar a la segunda cabecera obtenemos un error StreamCorruptedException y no podemos leer más datos.

La solución que he encontrado a esto consiste en hacernos nuestro propio ObjectOutputStream, heredando del de java y redefiniendo el método writeStreamHeader() para que no haga nada.

Todo esto está un poco más detallado en http://www.geocities.com/chuidiang2/ficheros/ObjetosFichero.html

1 comentario:

Anónimo dijo...

Bueno eso explica por que un archivo escrito sin ser "objeto", no puede ser leido por esta clase ObjectOutputStream... de manera que para archivos que no sean objeto es mejor para la lectura y escritura los BufferedReader y el metodo readLine() ... >_>