How can I keep the objects introduced in a binary object file?
This is the code I have done so far:
Scanner input=new Scanner(System.in);
String nom;
String apellido;
String barrio;
String DNI;
String FILENAME = "clientes.data";
File file = new File (FILENAME);
ObjectOutputStream output = null;
try
{
if (!file.exists())
output = new ObjectOutputStream (new FileOutputStream (FILENAME));
else
output = (new FileOutputStream (FILENAME,));
output.writeObject(peluqueria);
System.out.println("Operación de escritura terminada");
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
if (output != null)
{
try
{
output.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
The class
FileOutputStream
has a constructor with two parameters:If the second parameter receives a
true
, the data will be added to the end of the file and not to the beginning. However, this would not be the solution.We check it this way:
Imagine that the code above is in a called method
write
and then you call it three times. What will happen? Well, the serialized information will be added to the end of the file. However, the problem comes when we try to deserialize the object for the second time, since the Java virtual machine will throw the following exception:This is because the ObjectOutputStream class's parameterized constructor creates a header (the constructor implicitly calls the writeStreamHeader method ) of information and adds it to the file every time we want to write to it, and that's the problem, that this header should only be created only once (at the beginning of the file), otherwise we won't be able to deserialize more than one object.
Solution: We have to create our own class
ObjectOutputStream
, in which we will have to override the methodwriteStreamHeader
(since this method is responsible for creating the header).So the algorithm would look like this:
1.- Our custom class must inherit from
ObjectOutputStream
.2.- We will create a parameterized constructor in which it will receive the path where the file is located.
3.- We will invoke the parameterized constructor of the base class and later we will call a method (the name of this method will be
createFile
), in which it will return an object of typeFileOutputStream
.4.- In the method definition
createFile
, we verify if the file really exists, if it is true, we assign the value oftrue
to a boolean variable and finally, we create an instance of typeFileOutputStream
.The fourth step must be fulfilled before the constructor of the base class calls
writeStreamHeader
, since we will only create the header when the file does not exist (this is because the file must only have one header), otherwise there will be no header. need to callwriteStreamHeader
the class methodObjectOutputStream
.The definition of our custom class would look like this in Java:
Note: If you want to know why the method
createFile
is static, I recommend reading this: Cannot reference "X" before Supertype Constructor has been called .The way to use it would be like this:
As of Java 7 we can make use of ARM blocks . This Java feature saves us from manually closing resources.
The code would now look like this:
Conclusion:
With our solution we achieve that the header is only created once and additionally, we will not have problems when reading the file, because it will only have a header at the beginning.
In Java, a flag (a boolean) is usually used to indicate if the file is going to be overwritten (false) or if it is going to be appended (true)
Test:
I hope it works for you.