I am making a project where I need to save data to binary file using serilazation. I know how to read and write parameterized ArrayList using ObjectInputStream, ObjectOutputStream and FileInputStream. However I have no idea how I would go about updating ArrayList when new value is added or deleted.
import java.io.*;
import java.util.ArrayList;
public class testSerialization {
public static void main(String[] args){
String fileName = "test.bin";
ArrayList<Integer> integers = new ArrayList<>();
// Insert sample data
for (int i=0; i<10; i++){
integers.add(i);
}
try{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(fileName));
oos.writeObject(integers);
oos.flush();
oos.close();
}catch(Exception e){
System.out.println(e);
}
try {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName));
ArrayList<Integer> ps = (ArrayList<Integer>) ois.readObject();
System.out.println(ps);
ois.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
One way I can do it is that I just override all the data with updated data everytime I get a change, but there is probably better alternative solution
Related
This question already has answers here:
ObjectInputStream readObject in while Loop
(2 answers)
Closed 5 years ago.
I'm trying to save a a list of personnel in a .txt file using the ObjectOutputStream.
public void writeUsers(List<Personnel> userList) {
userSize = userList.size();
try {
FileOutputStream fos = new FileOutputStream(userFile);
ObjectOutputStream oos = new ObjectOutputStream(fos);
for (Personnel user : userList){
oos.writeObject(user);
}
oos.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
To read the file I use the following method:
public List<Personnel> readUsers() {
List<Personnel> userList = new ArrayList<Personnel>();
try {
FileInputStream fis = new FileInputStream(userFile);
ObjectInputStream ois = new ObjectInputStream(fis);
for(int i = 0; i < userSize; i++){
System.out.println("Entering loop");
userList.add((Personnel)ois.readObject());
}
System.out.println(userList.size());
ois.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return userList;
}
My problem is that I can't read an existing file with the read method without using the writeUser() method before because of the attribute userSize that is defined in writeUser() and then used in the loop in readUser().
for(int i=0; i < userSize; i++)
Is there something I can do to get the quantity of objects in my file?
Thanks for your time!
You loop until you get an EndOfFile Exception:
while(true) {
try {
userList.add((Personnel) ois.readObject());
} catch (EOFException e) {
// end of file reached
};
}
Simple answer: don't loop. Just write the entire collection as a single object, and read it back ditto.
Appended are my little utility functions for serialising objects. I just encountered following problem:
I renamed a package and suddenly I get a java.lang.ClassCastException when opening my app and trying to read serialised data...
Can I somehow solve that? I would like my serialisations to be working after a renaming, can I do something to implement this? Via some versioning for example?
Here are my two simple functions I use currently:
public static String serialize(Object object)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try
{
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
oos.flush();
oos.close();
} catch (IOException e)
{
L.e(StringUtil.class, e);
}
return Base64.encodeToString(baos.toByteArray(), 0);
}
public static <T> T deserialize(String serializedObject, Class<T> clazz)
{
if (serializedObject == null)
return (T)null;
byte [] data = Base64.decode(serializedObject, 0);
Object o = null;
try
{
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data));
o = ois.readObject();
ois.close();
}
catch (IOException e)
{
L.e(StringUtil.class, e);
}
catch (ClassNotFoundException e) {
L.e(StringUtil.class, e);
}
return (T)o;
}
I can suggest next options:
add support to your deserialize method to deal with old package names
convert byte [] data to String
replace old package name with new in deserialized data (with regexp)
continue to deserialize with ObjectInputStream
I'm basically making a journal app where each individual journal entry needs to persist, and I would like to keep all entries in a single file.
I've seen tons of tutorials on serializing a single object and so I came up with this solution, (which doesn't work) but even if I manage to fix it, it feels like a sloppy solution.
(Here I'm trying to serialize an arraylist, and each time I save an entry, i de-serialize the list and add the new entry to the list before serializing again)
To clarify, my question is: s this a good way to save objects to the same file, on multiple occasions?
Or does anyone have some tips about something else I should try, links to videos or documentation regarding this is also appreciated.
public class Serializer
{
//Calls readFile and adds the returned entries to an ArrayList
//Add the target object to the list and write to the file
public static void writeToFile(Object target)
{
ArrayList entries = new ArrayList();
entries = readFile();
entries.add(target);
String filename = "entries.bin";
FileOutputStream fileOut = null;
ObjectOutputStream objOut = null;
try
{
fileOut = new FileOutputStream(filename);
objOut = new ObjectOutputStream(fileOut);
objOut.writeObject(entries);
objOut.close();
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
//Reads the file and returns all entries in a list
public static ArrayList readFile ()
{
ArrayList persistedEntries = new ArrayList<>();
String filename = "entries.bin";
FileInputStream fileIn = null;
ObjectInputStream objIn= null;
try
{
fileIn = new FileInputStream(filename);
objIn = new ObjectInputStream(fileIn);
persistedEntries = (ArrayList) objIn.readObject();
objIn.close();
}
catch(IOException ex)
{
ex.printStackTrace();
}
catch(ClassNotFoundException ex)
{
ex.printStackTrace();
}
return persistedEntries;
}
}
Is this a good way to save objects to the same file, on multiple occasions?
I would argue no. This is because your method writeToFile or more accurately appendToFile can introduce strange behaviour in edge cases (such as entries.bin having an unexpected object). I would argue for this:
Use writeToFile(ArrayList<Object> target) to overwrite the file with the specified array. Then add a method appendToFile(Object target) that handles the process of reading from entries.bin from the disk, appending target then writing the array to the disk. This has the advantage of separating any logic related to 'merging' the new object target with the file on disk, and the actual logic of writing to the entries.bin file.
If just a learning exercise I would go with the above. Potential resource
Adding a reformatted version:
public class Serializer
{
private String filename;
// pass in "entries.bin"
public Serializer(String filename) {
this.filename = filename;
}
public void append(Object target) {
// readfile will return at least empty arraylist
ArrayList entries = readFile();
entries.add(target);
serialize(entries);
}
public void serialize(ArrayList entries)
{
FileOutputStream fileOut = null;
ObjectOutputStream objOut = null;
try
{
fileOut = new FileOutputStream(filename);
objOut = new ObjectOutputStream(fileOut);
objOut.writeObject(entries);
objOut.close();
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
//Reads the file and returns all entries in a list
public ArrayList deserialize ()
{
ArrayList persistedEntries = new ArrayList<>();
FileInputStream fileIn = null;
ObjectInputStream objIn = null;
try
{
fileIn = new FileInputStream(filename);
objIn = new ObjectInputStream(fileIn);
Object result = objIn.readObject();
if (!(result instanceof ArrayList)) {
// read object is not an arraylist
}
persistedEntries = (ArrayList) objIn.readObject();
objIn.close();
}
catch(IOException ex)
{
ex.printStackTrace();
}
catch(ClassNotFoundException ex)
{
ex.printStackTrace();
}
return persistedEntries;
}
}
I have certain arraylists in my programm which I would like to write into a file so I can read them when starting the programm for a second time.
Currently it works for an arraylist of persons.
The reading part:
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("test.txt"));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
team.setPersonList((ArrayList<Person>) ois.readObject());
The writeToFile class:
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.ArrayList;
public class WriteToFile {
public void write(ArrayList<Person> Data ) throws IOException, ClassNotFoundException{
// create a new file with an ObjectOutputStream
FileOutputStream out = new FileOutputStream("test.txt");
ObjectOutputStream oout = new ObjectOutputStream(out);
// write something in the file
oout.writeObject(Data);
// close the stream
oout.close();
// create an ObjectInputStream for the file we created before
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("test.txt"));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// read and print what we wrote before
System.out.println("" + ois.readObject());
ois.close();
}
}
In main:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) throws ClassNotFoundException, IOException{
BufferedReader scan = new BufferedReader(new InputStreamReader(System.in));
Team team = new Team(scan);
new InlogSystem(team, scan);
ArrayList<Person> playersData = team.getPersonList();
WriteToFile x = new WriteToFile();
x.write(playersData);
scan.close();
}
}
So this is the working part,
Now i want an arraylist of Strings to write into another txt file (not test like the personlist) using the same writeToFile class.
Obviously the writemethod only works for an arraylist of type person, and it always saves the array into "test.txt".
How do I write this arraylist without making a new method and having alot of ambigious code?
Thanks alot!
You can change the parameter type ArrayList<String> to ArrayList<?> or even List<?> or, what I would suggest, to Object. Then, your method is capable of writing arbitrary objects.
Using generics is useless here: It provides compile-time type checking, which wouldn't be used in your method.
By the way, your exception handling is very bad. I suggest you catch and re-throw the ClassNotFoundException as an IOException; FileNotFoundException is just a subclass of IOException and needn't be catched seperately - and why do you catch an IOException at all when your method is declared as throws IOException ?
Amend your method to accept List instead, where T is parametrized object. Refer to generics documentation
Use a generic method and pass the filename as a parameter i.e.
public <T implements Serializable> void write(ArrayList<T> Data, String filename) throws IOException {
// create a new file with an ObjectOutputStream
FileOutputStream out = new FileOutputStream(filename);
ObjectOutputStream oout = new ObjectOutputStream(out);
// write something in the file
oout.writeObject(Data);
// close the stream
oout.close();
// create an ObjectInputStream for the file we created before
ObjectInputStream ois = null;
ois = new ObjectInputStream(new FileInputStream("test.txt"));
// read and print what we wrote before
System.out.println("" + ois.readObject());
ois.close();
}
i am trying to write and read a vector to a text file. I made a class WriteVectorToFile (shown below) which makes a vector containing objects of a class called Car. The class Car implements Serializable and only contains information with setter and getter methods. In the WriteVectorToFile class i have made a createVector() method and writetoFile() method and they work. The problem in the readtoFile() method and it gives out an error (listed below). I want to know what am i doing wrong and what is causing the problem.
The error :
java.lang.NullPointerException
at WriteVectorToFile.readtoFile(WriteVectorToFile.java:73)
at WriteVectorToFile.main(WriteVectorToFile.java:110)
at __SHELL1.run(__SHELL1.java:6)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at bluej.runtime.ExecServer$3.run(ExecServer.java:725)
Code:
import java.io.*;
import java.util.Vector;
public class WriteVectorToFile{
private Car car1;
private Vector garage;
private File myFile;
private FileOutputStream out;
private FileInputStream in;
private ObjectInputStream objin;
private ObjectOutputStream objout;
public WriteVectorToFile(){
this.myFile = new File("E:/JAVA/My Java Programs/MyVectorFile.txt");
try{
myFile.createNewFile();
System.out.println("New File --> Success.");
}catch(IOException e){
e.printStackTrace();
System.out.println("New File --> Fail.");
}
}
private void writetoFile(){
try{
out = new FileOutputStream(myFile);
objout = new ObjectOutputStream(out);
}catch(FileNotFoundException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
try{
objout.writeObject(garage);
objout.close();
System.out.println("Write File --> Success.");
}catch(IOException e){
System.out.println("Write File --> Fail.");
e.printStackTrace();
}
}
private void readtoFile(){
try{
FileInputStream in = new FileInputStream(myFile);
ObjectInputStream objin = new ObjectInputStream(in);
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
// Object obj = null;
Vector tempVec = new Vector();
try{
ERROR Line 73 : tempVec = (Vector) objin.readObject();
objin.close();
System.out.println("Read File --> Success.");
}catch(Exception e){
System.out.println("Read File --> Fail.");
e.printStackTrace();
}
//Car tempg = new Car();
//tempg = (Car) vecNew.firstElement();
//System.out.println(tempg.toString());
//System.out.println(((Car)(vecNew.firstElement())).toString());
}
private void createVector(){
this.garage = new Vector();
// To create a vector with a specific datatype add <type>
// Vector garage = new Vector<Car>();
car1 = new Car("3245","Toyota","Ferry23",(double)34500);
this.garage.add(car1);
this.garage.add(new Car("3232","Fiat","MozoZ3",(double)25000));
this.garage.add(new Car("2345","Mazda","ZenFix",(double)13700));
}
public static void main (String[] args){
WriteVectorToFile test = new WriteVectorToFile();
test.createVector();
test.writetoFile();
test.readtoFile();
}
}
Firstly, apologies as I cannot post it as comment so putting it into an answer block:
Your problem is the scope mismatch involving try-catch blocks . If you have done any C++, the objects are passed by value or reference so this could have been avoided very conveniently. But Java passes everything by value so when you do:
try{
FileInputStream in = new FileInputStream(myFile);
ObjectInputStream objin = new ObjectInputStream(in);
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
The object objin is created inside try-catch scope which is NOT the same when you use it in:
tempVec = (Vector) objin.readObject();
objin.close();
System.out.println("Read File --> Success.");
}catch(Exception e){
System.out.println("Read File --> Fail.");
e.printStackTrace();
}
So the solution is put everything in one "try" block and catch all the exceptions seperately (or even together using Exception as superclass [not a good practice]). This should do the job. Tell us if you manage to solve it anyway.
Because you have defined the private ObjectInputStream objin; as instance variable and it is null. So when you invoke objin.readObject(); on null will throw NullPointerException. Inside the readtoFile() method, you do something like this:
try{
FileInputStream in = new FileInputStream(myFile);
ObjectInputStream objin = new ObjectInputStream(in);
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
That defines a new local ObjectInputStream objin = new ObjectInputStream(in); inside try block, which is invisible to the code tempVec = (Vector) objin.readObject(); ouside try-catch block. Here objin refers to the instance variable declared at instance level and it is null. To correct it change
ObjectInputStream objin = new ObjectInputStream(in);
to
objin = new ObjectInputStream(in);
inside the try block.