How to append objects with ObjectOutputStream without deleting file content?

2

The question is that, I do not attach the created objects to those already contained in the file, but I overwrite them ... Does anyone know how to solve it? I leave you the code that does the function of saving the objects.

public static void EscriureFitxer(String nom,String cognom1,String cognom2,String dni,File FILE_NAME,ArrayList<Alumne> list){
                Alumne a = new Alumne (nom,cognom1,cognom2,dni);
                list.add(a);
                ObjectOutputStream objectOutput = null;
                try {
                    objectOutput = new ObjectOutputStream(new FileOutputStream(FILE_NAME));
                    objectOutput.writeObject(list);

                    System.out.println("S'ha generat el fitxer " + FILE_NAME);

                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if(objectOutput != null) {
                        try {
                objectOutput.close();
                        } catch (IOException ignored) {
                        }
                    }
                }
}


public static void LlegirFitxer(File FILE_NAME){
        ObjectInputStream objectInput = null;

                try {
                    objectInput = new ObjectInputStream(new FileInputStream(FILE_NAME));

                    ArrayList<Alumne> list = (ArrayList<Alumne>) objectInput.readObject();
                    for(int u=0;u<list.size();++u) {
                        System.out.println(u + " --> " + list.get(u));
                    }

                    objectInput.close();
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } finally {
                if(objectInput != null) {
            try {
                        objectInput.close();
            } catch (IOException ignored) {
            }
                }
                }       
}
    
asked by Eduu Borràs Ruiz 24.01.2017 в 12:20
source

3 answers

1

The FileOutputStream class offers a constructor with two parameters : FileOutputStream(File file, boolean append) where the second argument boolean append indicates whether you want to rewrite the file or continue writing from the end. Add the parameter in true in your code:

objectOutput = new ObjectOutputStream(new FileOutputStream(FILE_NAME, true));

Additionally, if you work with Java 7, you can use the try-with-resources and avoid calling the close method manually:

//el bloque try va a cerrar el stream por ti
try (ObjectOutputStream objectOutput = new ObjectOutputStream(
         new FileOutputStream(FILE_NAME, true))) {
    objectOutput.writeObject(list);
    System.out.println("S'ha generat el fitxer " + FILE_NAME);
    //adicionalmente, el bloque catch puede contener más de un tipo de excepción separadas por pipe 
} catch (FileNotFoundException | IOException e) {
    e.printStackTrace();
}
    
answered by 24.01.2017 в 14:21
0

This occurs because the writeObject method does not respect what is previously written in the file. You can create a method to read the file before overwriting it:

public String leeArchivo (String ruta) {

    File file = new File(ruta);
    FileInputStream fis = null;
    String contenido="";

    try {
        fis = new FileInputStream(file);

        int content;
        while ((content = fis.read()) != -1) {
            // Convertir a char para guardarlo
            contenido += Character.toString((char) content));
        }
        return contenido;

    } catch (IOException e) {
        e.printStackTrace();
        return null;
    } finally {
        try {
            if (fis != null)
                fis.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

And in your method that you write in the file, write the result of reading the file, before writing the new one.

String contenido = leeArchivo(FILE_NAME);
objectOutput = new ObjectOutputStream(new FileOutputStream(FILE_NAME));
objectOutput.writeBytes(contenido);
objectOutput.writeObject(list);
    
answered by 24.01.2017 в 12:42
0

Good, I think I understood what you are doing after going around for a while (and having answered wrongly before).

As I see that you have the program written, without seeing how you make the calls to the methods, you call the function that writes EscriureFitxer with the parameters that a Student has, the path of a File where you write and an ArrayList of Alumne that you write in the file. Seen what you do in the method, you could directly pass a Alumne object to it and then add it to the list, or go directly to the list with the Student added, but that is irrelevant.

As you have it right now, what you do is overwrite the data that was there, because, as you were told, so that when you write do not write over what was there, in the FileOutputStream constructor you have to put a second parameter that is true, so that it append to what was there.

If I add the parameter true to me it works correctly to add, eye, just the add.

Now, before in your program you had this: ArrayList<Alumne> list = (ArrayList<Alumne>) objectInput.readObject(); That reads an object, which in this case is a list, but only reads one. Even if the program worked, I would only read the first list you add, not the others.

What I do not know is if your idea is to have a single list in your file or have more than one, but as you have planned right now you would have many, but you are only reading one.

If you would like to have only one list, you do not have to make the file add new things, if not write the list that already had the new one, but for that in the writing method you would have to recover the list and add the new element.

I will interpret that you want to add new lists to comment on a failure that I see that it is perhaps important to point out.

If in the constructor of the FileOutputStream we put the second parameter so that it overwrites new FileOutputStream(FILE_NAME, true) we will have to do something to be able to read all the lists that have been stored. Something like this:

Object actual = null;
ArrayList<Alumne> lista = null;
while((actual = objectInput.readObject()) != null) {
    lista = (ArrayList<Alumne>) actual;
    for (int u = 0; u < lista.size(); ++u) {
       System.out.println(u + " --> " + lista.get(u).getNom());
    }
}

This would iterate over all the lists until there are no more. By the way, you would have to control EOFException by the time you reach the end of the file.

But there is a problem with this. When writing a file with objects, a header is written at the beginning. If you write once and try to read there will be no failure. The program sees the header and will read everything perfectly. If you try to add something new to the file it will write after the existing one a new header. When you try to read it will use the first header and read the first value, but when you try to read the second one, written with another header, it will launch a Corrupt header error .

The solution to this problem is that every time you want to write something new you create a new first thing to do is create a reading and writing channel and read and write everything (without closing the writing channel) and when you reach the end write the new and then close the channels.

As I suspect that your intention is that there is only one list in your file, I propose this method to write:

public static void EscribirFichero(String nom, String cognom1,
    String cognom2, String dni, File FILE_NAME) {

    ObjectOutputStream objectOutput = null;
    ObjectInputStream objectInput = null;
    ArrayList<Alumne> list = new ArrayList<Alumne>();
    try {
        if(FILE_NAME.exists()) {
            objectInput = new ObjectInputStream(new FileInputStream(FILE_NAME));
            list = (ArrayList<Alumne>) objectInput.readObject();
        }

        Alumne a = new Alumne(nom, cognom1, cognom2, dni);
        list.add(a);

        objectOutput = new ObjectOutputStream(new FileOutputStream(FILE_NAME));
        objectOutput.writeObject(list);

        System.out.println("Se ha generado el fichero " + FILE_NAME);

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } finally {
        if (objectOutput != null) {
            try {
                objectOutput.close();
            } catch (IOException ignored) {
            }
        }
    }
}

It will read the list that exists, add the new element and write the new list in the file.

To read I used this method, slightly modified:

public static void LeerFichero(File FILE_NAME) {
    ObjectInputStream objectInput = null;

    try {
        objectInput = new ObjectInputStream(new FileInputStream(FILE_NAME));

        Object actual = null;
        ArrayList<Alumne> lista = null;
        while((actual = objectInput.readObject()) != null) {
            lista = (ArrayList<Alumne>) actual;
            for (int u = 0; u < lista.size(); ++u) {
                System.out.println(u + " --> " + lista.get(u).getNom());
            }
        }

        objectInput.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch(EOFException e) {

    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } finally {
        if (objectInput != null) {
            try {
                objectInput.close();
            } catch (IOException ignored) {
            }
        }
    }
}

I hope I have been helpful this time:)

    
answered by 18.12.2017 в 19:03