reading data from a serialized file containing multiple objects - java

I'm trying to read data from a file containing multiple objects of a class. But I'm getting null pointer exception while adding objects to list. can anyone help?
Here's the code:
//I'm following the same approach, but getting null Pointer exception while
//adding the object to a list. I'll post my code below. Can anyone help?
public class DeserializingMultipleObjects {
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws IOException {
//create few objects of student class and serialize them in a single file
Student st1= new Student(1, "abhishek", 24, 1);
Student st2= new Student(2, "Prashant",23,3);
Student st3= new Student(3,"Gayatri",22,2);
Student st4= new Student(4,"Ankul",23,4);
FileOutputStream fout= null;
FileInputStream fin= null;
ObjectInputStream oin=null;
ObjectOutputStream oout= null;
List <Student> studentList=null;
try{
fout= new FileOutputStream("Student.ser");
oout= new ObjectOutputStream(fout);
oout.writeObject(st1);
oout.writeObject(st2);
oout.writeObject(st3);
oout.writeObject(st4);
//objects have been serialized. Now read them and populate in a list
fin= new FileInputStream("Student.ser");
oin= new ObjectInputStream(fin);
boolean flag=false;
while(!flag){
if(oin.readObject()==null || oin.readObject().equals("")){
flag=true;
}
else{
studentList.add((Student)oin.readObject());
}
}
}
catch (ClassNotFoundException ex) {
Logger.getLogger(DeserializingMultipleObjects.class.getName()).log(Level.SEVERE, null, ex);
} finally{
if(fout !=null) try {
fout.close();
} catch (IOException ex) {
Logger.getLogger(DeserializingMultipleObjects.class.getName()).log(Level.SEVERE, null, ex);
}
if(oout !=null){
oout.close();
}
if(fin !=null){
fin.close();
}
if(oin !=null){
oin.close();
}
for(Student student: studentList){
System.out.println(student.name);
}
}
}
}

You read your object three times per iteration.
while(!flag){
Student st = oin.readObject();
if(st == null){
flag=true;
}
else{
studentList.add(st);
}
}

List <Student> studentList=null; is giving the error. When you reach the part where you want to add to studentList with studentList.add((Student)oin.readObject());, the list is a null pointer because you initialized it as such.
You might want to initialize the list to something else than null, e.g. List<Student> studentList = new ArrayList<Student>();

Several mistakes:
You forgot to close the ObjectOutputStream before starting to read from the file
Every time you call readObject(), you read the next object from the stream, so the following lines:
if(oin.readObject()==null || oin.readObject().equals("")){
flag=true;
}
else{
studentList.add((Student)oin.readObject());
}
read 2 or three objects, instead of reading just one. They should be
Object read = oin.readObject()
if(read == null || read.equals("")){
flag=true;
}
else {
studentList.add((Student) read);
}
But readObject() will never return null, and there's no way it returns an empty string, since you have only written instances of Student in the stream.
Everything would be much easier if you just stored your 4 students in a List<Student> and serilaized this list. Deserializing would simply consist in reading one object (so, no loop necessary): the list of students.
Also, closing the ObjectOutputStream will automatically close the FileOutputStream. Same for the ObjectInputStream. So closing the file streams is unnecessary. For a much cleaner and safer resource handling, you should use try-with-resources.

Related

Adding console input to ArrayList in Java

I'm trying to add items from the console input and scanner input to arraylists in java.
(To run the program user types Program ID)
The problem is that each time I run the program the contents of the arraylists update to only what has been entered that time. I would like the arraylists to contain all of the inputs that have been entered.
public class User{
private static List<String> listNames = new ArrayList<String>();
private static List<Integer> listIds = new ArrayList<Integer>();
public static void main(String[] args)
{
int tempID = 5000;
if (args.length>0) tempID= Integer.parseInt(args[0]);
System.out.println("Login "+tempID);
Scanner scanner = new Scanner(System.in);
System.out.print("Enter your Name : ");
tempName = scanner.nextLine();
User n = new User();
n.ID= tempID;
n.name = tempName;
listIds.add(n.ID);
listNames.add(n.name);
}
}
}
Does anyone know if this is possible?
Everytime you run the program it is going to initialize a different array. To solve this, you can store your data in a database such as MySQL or Oracle. But a more efficient way to solve this is that to save your ArrayList as an object locally using java.io.ObjectInputStream and java.io.ObjectOutputStream
I wrote the following 2 functions
public static ArrayList<Object> loadArrayList(String filename)
{
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream(filename));
ArrayList<Object> arr = (ArrayList<Object>) ois.readObject();
return arr;
} catch (IOException e) {
e.printStackTrace();
return null;
} catch (ClassNotFoundException e) {
e.printStackTrace();
return null;
} finally {
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void saveArrayList(ArrayList<Object> arr, String filename)
{
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream(filename));
oos.writeObject(arr);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (oos != null) {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Call saveArrayList with the first argument is your ArrayList instance and the second argument the filename. You can then load from your local file system using the loadArrayList method with the argument is your filename.
In your case, just call the saveArrayList method when your user exits the program and call the loadArrayList to get all your elements from the previous inputs to resume the user's progress
Every time you compile your program you create new Arrays. So you need another way of saving your inputs like in a SQL Database or you can run your program infinitely with a loop and ask each time for a new entry and collect it with the scanner like you already did but with that method, you can do nothing with the array entries because your asking for entries never stops.

ObjectInputStream not reading full file after appending data

I am writing a small program that inserts customer details in ArrayList and write it in file.
The problem is with ObjectOutputStream I was able to append data in file with turning FileOutputStream("",true). But when I try to read data with ObjectInputStream it only reads data that was inserted at first instance. But data is being added to file.
Here is the code -
public void insertCustomer() throws IOException
{
Customer1=new customerDetails("1", "Moeen4", "654654", "asdf", "coding", "student", "65464", "3210");
Customer3=new customerDetails("3", "Moeen5", "888888", "asdf", "coding", "student2", "65464", "321022");
Customer4=new customerDetails("4", "Moeen6", "654654", "asdf", "coding", "student", "65464", "7890");
_list=new ArrayList<customerDetails>();
_list.add(Customer1);
_list.add(Customer3);
_list.add(Customer4);
customersList cl=new customersList();
cl.WriteObjectToFile(files._customers, _list);
ArrayList<customerDetails>li=new ArrayList<customerDetails>();
li= (ArrayList) cl.ReadObjectFromFile(files._customers);
for(int i=0;i<li.size();i++)
{ System.out.println(li.size());
System.out.println(li.get(i).Id);
System.out.println(li.get(i).name);
System.out.println(li.get(i).annual_Salary);
System.out.println(li.get(i).Company);
System.out.println(li.get(i).dateOfBirth);
System.out.println(li.get(i).phone_Number);
}
}
public void WriteObjectToFile(String filepath,Object serObj) {
try {
FileOutputStream fileOut = new FileOutputStream(filepath,true);
ObjectOutputStream objectOut = new ObjectOutputStream(fileOut);
objectOut.writeObject(serObj);
objectOut.close();
System.out.println("The Object was succesfully written to a file");
} catch (Exception ex) {
ex.printStackTrace();
}
}
public Object ReadObjectFromFile(String filepath) {
try {
FileInputStream fileIn = new FileInputStream(filepath);
ObjectInputStream objectIn = new ObjectInputStream(fileIn);
Object obj = objectIn.readObject();
objectIn.close();
System.out.println("The Object has been read from the file");
return obj;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
The real problem here is this:
FileOutputStream fileOut = new FileOutputStream(filepath, true);
ObjectOutputStream objectOut = new ObjectOutputStream(fileOut);
objectOut.writeObject(serObj);
You cannot append to an existing serialization like this. If you do get an exception when attempting to read any objects appended to a pre-existing (non-empty) file.
There is a trick / hack that allows you to append objects though; see Appending to an ObjectOutputStream. (The trick involves suppressing the writing of the object stream header. It is most easily done by overriding the method that does this.)
The other approach is to keep the ObjectOutputStream open between writeObject calls. However there are use-cases where that won't be possible.
Note that there is a semantic difference between these two approaches. The best way to explain it is that the first one behaves as if you called reset() each time you write an object; see the javadoc.
Another thing to note about your example is that your reader code only reads one object. If you want to read multiple objects, you need to call readObject in a loop. And that will only work if you have used the trick / hack above to avoid writing a spurious header.
As suggested the code is only reading the first object and you would need to use a loop to read all the objects from multiple writes.
However -
If you change the above code i.e. ReadObjectFromFile to use a loop this will lead to an StreamCorruptedException: invalid type code: AC. The ObjectOutputStream constructor writes a serialization stream header to the OutputStream i.e. the file, when it is closed and reopend using new ObjectOutputStream and new FileOutputStream(filepath, true) a new header will be written at the append point so you will get an exception as the header is only expected once at the beginning of the file
This will need to be handled e.g.
Use the same ObjectOutputStream for the duration
Override java.io.ObjectOutputStream.writeStreamHeader() to account for append to a file
Change the approach and use List<List<Object>> which you could read, add, write to as a whole.
Loop example would throw exception unless ObjectOutputStream approach is changed
public Object ReadObjectFromFile(String filepath) {
List<List<Object>> objects = new ArrayList<>();
FileInputStream fileIn = new FileInputStream(filepath);
ObjectInputStream objectIn = new ObjectInputStream(fileIn);
try {
while (true) {
List<Object> obj = (List<Object>) objectIn.readObject();
// This will throw StreamCorruptedException: invalid type code: AC
objects.add(obj);
System.out.println("The Object has been read from the file");
}
} catch (EOFException ex) {
// ENDS WHEN ALL READ
} finally {
fileIn.close();
objectIn.close();
}
return objects;
}
Sudo code List<List<Object>> approach -
public void readAndWrite() {
List<Object> customer = List.of(new CustomerDetails(...),
new CustomerDetails(...),
new CustomerDetails(...));
List<List<Object>> objects = readFromFile("existing-customer-file.txt");
objects.addAll(customer);
writeObjectToFile(objects);
}

Loading From File Error In Java?

I have to implement Object Files for a java project, however I am having trouble when it comes to loading the file (Save is all OK)
public static void loadStudentList() {
boolean endOfFile = false;
try {
// create a FileInputStream object, studentFile
FileInputStream studentFile = new FileInputStream("Students.obf");
// create am ObjectImnputStream object to wrap around studentStream
ObjectInputStream studentStream = new ObjectInputStream(studentFile) ;
// read the first (whole) object with the readObject method
Student tempStudent = (Student) studentStream.readObject();
while (endOfFile != true) {
try {
tempStudent = (Student) studentStream.readObject();
stud1.add(tempStudent);
}
catch(EOFException e) {
endOfFile = true;
}
}
studentStream.close();
//use the fact that the readObject throws an EOFException to check whether the end of eth file has been reached
}
catch(FileNotFoundException e) {
System.out.println("File not found");
}
catch(ClassNotFoundException e) { // thrown by readObject
/* which indicates that the object just read does not correspond to any class
known to the program */
System.out.println("Trying to read an object of an unkonown class");
}
catch(StreamCorruptedException e) { //thrown by constructor
// which indicates that the input stream given to it was not produced by an ObjectOutputStream object
System.out.println("Unreadable File Format");
}
catch(IOException e) {
System.out.println("There was a problem reading the file");
}
}
This is the code I used to load the files. The program will load ONLY the last 2 records in my file. The Idea is that I load all of them to an array list for future use in the program. Also I am not getting any of my catches back. Any help? Thanks :)
You never add to the list the first Student that you read
Student tempStudent = (Student) studentStream.readObject();
while (endOfFile != true)
{
try
{
tempStudent = (Student) studentStream.readObject();
stud1.add(tempStudent);
}
Remove the read before the while, like the code below
while (endOfFile != true)
{
try
{
Student tempStudent = (Student) studentStream.readObject();
stud1.add(tempStudent);
}
I am not sure if this will solve your problem
Why don't you add the objects to an ArrayList<Type> then write/serialize them to file
and then for reading/deserialize it, read the data into one ArrayList<Type>.
Then you could fetch your objects one by one from the ArrayList
This might be an easier trouble free way of doing it.
//Serialize
ArrayList<Student> students = new ArrayList<Student>();
//Add the student objects to the array list
File f = new File("FileName.ser");
ObjectOutputStream objOut = new ObjectOutputStream(new FileOutputStream(f));
objOut.writeObject(students);
//Deserialize
ArrayList<Student> students = new ArrayList<Student>();
ObjectInputStream objIn = new ObjectInputStream(new FileInputStream(new File("FileName.ser")));
students = (ArrayList<String>) objIn.readObject();

Parse String Output to File

The first part of this “Frankenstein-ed” Java works perfectly, however the second part outputs some jumbled nonsense. So the variable of result will be my input from the user. I had to first UpperCase the string before I did the parsing for some dumb reason, it’s hard when you come from the Database/Analysis background and know you do something in seconds and not get an error... I gave credit where credit is due within the code...
myfile.txt ---> [Ljava.lang.String;#19821f
import java.io.*;
/*http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#split%28java.lang.String%29*/
public class StringParser {
public static void main (String arg[])
throws FileNotFoundException {
String result = "eggs toast bacon bacon butter ice beer".toUpperCase();
String[] resultU = result.split("\\s");
String[] y = resultU;
{
for (int x=0; x< resultU.length; x++)
System.out.println(resultU[x]);
/*http://www.javacoffeebreak.com/java103/java103.html#output*/
FileOutputStream out; // declare a file output object
PrintStream p; // declare a print stream object
try
{
// Create a new file output stream
// connected to "myfile.txt"
out = new FileOutputStream("myfile.txt");
// Connect print stream to the output stream
p = new PrintStream( out );
p.println (resultU);
p.close();
}
catch (Exception e)
{
System.err.println ("Error writing to file");
}
}
}
}
Do you realize you're overwriting the same file for each element in your array?
You should use
out = new FileOutputStream("myfile.txt", true); // appends to existing file
As well as printing the actual element, not the String representation of the whole array
p.println(resultU[x]); // resultU without index prints the whole array - yuk!
Although you should probably update your code to only create the output File once and just write each element of the array to the same output stream, as the current method is a bit inefficient.
Something like
public static void main(String[] args) {
String result = "eggs toast bacon bacon butter ice beer".toUpperCase();
PrintStream p = null;
try {
p = new PrintStream(new FileOutputStream("myfile.txt"));
for (String s : result.split("\\s")) {
p.println(s);
p.flush(); // probably not necessary
}
} catch (Exception e) {
e.printStackTrace(); // should really use a logger instead!
} finally {
try {
p.close(); // wouldn't need this in Java 7!
} catch (Exception e) {
}
}
}
You have to iterate the array and write each element one after one.
FileOutputStream out; // declare a file output object
PrintStream p; // declare a print stream object
try
{
out = new FileOutputStream("myfile.txt");
p = new PrintStream( out );
for(String str:resultU)
{
p.println (str);
}
p.close();
}
catch (Exception e)
{
System.err.println ("Error writing to file");
}
Your line
p.println (resultU);
is printing a string representation of the array itself, not the elements in it. To print the elements, you'll need to loop through the array and print them out individually. The Arrays class has a convenience method to do this for you, of course.
That "jumbled non-sense" is the Strings location in memory, but that's not important right now.
The solution to your problem is this:
try {
FileOutputStream out = new FileOutputStream("myfile.txt", true);
PrintStream = new PrintStream(out);
for(String s : resultU)
p.println(s);
p.close();
} catch(Exception e) {
e.printStackTrace();
}
This replaces your entire for loop.

handling EOFException in java

I have created a method in my java assignment to write into a file from a LinkedList (I used serialization) , then I have created another method to read the file into the inkedList. The following is my method's body:
try {
FileInputStream fin = new FileInputStream("c:\\Info.ser");
ObjectInputStream ois = new ObjectInputStream(fin);
Employee e = (Employee) ois.readObject();
linkP.add(e);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
but it doesnt work right. I think this part:
Employee e = (Employee) ois.readObject();
linkP.add(e);
reads only the first object of the file into the linkedlist and ignores other objects. I surrounded it for loop and while loop several times but it causes EOFException. How can I change my method to read all of the file's objects into the LinkedList?
If you used LinkedList for serialization you should expect a LinkedList to deserialize:
linkP= (LinkedList) ois.readObject();
instead of
Employee e = (Employee) ois.readObject();
linkP.add(e);
The easiest way is to include the size of the list as the first thing written to the file. When you read the file, the first thing you retrieve is the size. Then you can read the expected number of objects.
Are you sure that the serialized file contains all of the elements? It looks to me like you might only be serializing one.
Note: Please also add the code where you create the info.ser file, since you may have corrupted the ObjectOutputStream by closing/reopening it for each object.
But to answer your question, the proper way of doing it (without catching exceptions) would be:
#Test
public void testSerializingListByEntries() throws Exception {
List<Serializable> list = new ArrayList<Serializable>();
list.add(new Date());
list.add(new Date());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeInt(list.size()); // Magic
for(Serializable o : list) {
oos.writeObject(o);
}
oos.close();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
int count = ois.readInt();
List<Object> newList = new ArrayList<Object>();
for(int i = 0; i < count;i++) {
newList.add(ois.readObject());
}
ois.close();
assertEquals(list,newList);
}
Yes, you need to close the streams yourself of course. Omitted for readability.
Would probably need to see how you're writing in the first place but generally:
ObjectInputStream is = null;
try
{
is = new ObjectInputStream(new FileInputStream("c:/Info.ser"));
Object object = null;
while ((object = is.readObject()) != null)
{
linkP.add(object);
}
}
catch(Exception e)
{
//Whatever you need to do
}
finally
{
//Never forget to close your streams or you'll run into memory leaks
try
{
if (is != null)
{
is.close();
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
Also, its probably better practice for you to handle the exceptions individually but I can't really tell what the streams throw so replace the (Exception e) with everything else.
surround Employee e = (Employee) ois.readObject();
linkP.add(e);
with a for loop as you suggested and surround the .readObject call with a try/catc(EOFException)
Just catch EOFException separately inside your reading loop and process it accordingly, i.e. break out of the loop.

Categories

Resources