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.
Related
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);
}
I am working on a UI which reads serialized object from zookeeper, deserializes it and then converts it into JSON. For some reason I am not able to deseerialize the MQTopic object. But I am able to do the same with other objects.
This is the part which converts the byte[] into the MQTopic object.
if (tester != null && tester.contains("com.ibm.mq.jms.MQTopic")) {
System.out.println(getValue());
ByteArrayInputStream in = new ByteArrayInputStream(this.value);
ObjectInputStream is = new ObjectInputStream(in);
System.out.println("after deserializing..");
topic = (MQTopic) is.readObject();
System.out.println("after typecasting..");
System.out.println(topic.getTopicName());
System.out.println(topic.toString());
is.close();
in.close();
}
Here value is a byte array of the object after serialization.
Nothing runs after topic = (MQTopic) is.readObject(); . Not even the print statements. The program neither terminates nor an exception is thrown or caught.
EDIT : Whole Method
public String getStrValue() {
FtpConnectionInfo ftp = null;
MQTopic topic = null;
try {
String tester = new String(this.value, "UTF-8");
if (tester != null && tester.contains("FtpConnectionInfo")) {
ByteArrayInputStream in = new ByteArrayInputStream(this.value);
ObjectInputStream is = new ObjectInputStream(in);
ftp = (FtpConnectionInfo) is.readObject();
in.close();
is.close();
Gson gson = new Gson();
return gson.toJson(ftp);
} else if (tester != null
&& tester.contains("com.ibm.mq.jms.MQTopic")) {
ByteArrayInputStream in = new ByteArrayInputStream(this.value);
ObjectInputStream is = new ObjectInputStream(in);
System.out.println("after deserializing..");
topic = (MQTopic) is.readObject();
System.out.println("after typecasting..");
System.out.println(topic.getTopicName());
System.out.println(topic.toString());
is.close();
in.close();
} else {
return new String(this.value, "UTF-8");
}
} catch (UnsupportedEncodingException ex) {
System.out.println("unsupported error ");
ex.printStackTrace();
//logger.error(Arrays.toString(ex.getStackTrace()));
} catch (Exception e) {
System.out.println("Exception in new logic.");
e.printStackTrace();
}
System.out.println("im out of try");
return null;
}
The FTP if loop works fine, but the Topic loop does not work beyond typecasting.
EDIT 2: This how the other team stores the object into Zookeeper
public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(out);
os.writeObject(obj);
return out.toByteArray();
}
The byte[] is stored in Zookeeper and that is what I am retrieving in my UI.
EDIT 3: I did a debug of the process and at the point where is is called, these are the values. Can anyone tell me if the object is right ?
You're doing this wrong. You should deserialize the object first, and then use instanceof to see what type it is. Converting binary data to String is poor practice at the best of times.
Your actual symptom is not credible. An exception must be thrown, or else you are blocking earlier than stated.
ObjectInputStream's readObject is a blocking method. First check using the available method if there is something to read without blocking.
available would most probably return 0 in this case.
This might be only half the solution you are looking for, but I think this would let you know if you have anything to read or not.
I have a block of code, that deserializes multiple objects from file. How can i avoid using a while(true)?
ObjectInputStream in = new ObjectInputStream(new FileInputStream(
filename));
while (true) {
try {
MyObject o = (MyObject) in.readObject();
// Do something with the object
} catch (EOFException e) {
break;
}
}
in.close();
You should write either a collection (with a size), or a put a marker before each object:
try {
for (;in.readBoolean();) {
MyObject o = (MyObject) in.readObject();
}
} catch (EOFException e) {
// ...
}
When you write your object, write a boolean just before (it will however take 1 byte if I do remember well that part):
for (MyObject o : iterable) {
out.writeBoolean(true);
out.writeObject(o);
}
out.writeBoolean(false);
If iterable is a collection or map, you can use default serialization:
out.writeObject(iterable); // default collection serialization
Beside, don't catch an exception for each item, catch it globally (especially EOFException!): it is better for performance reasons.
I don't know if you work with Java 7, but your code + my for loop can be written like this:
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream( filename))) {
for (;in.readBoolean();) {
MyObject o = (MyObject) in.readObject();
}
} catch (EOFException e) {
// ...
}
// no need to close, the try-with-resources do the job for you.
How can i avoid using a while(true)?
You can't.
More to the point, why do you think you want to?
This is a classic example of the tail wagging the dog. EOFException is thrown to indicate end of stream. Ergo you have to catch it, and ergo you have to loop until it is thrown, ergo you have to use while (true) or one of its cognates.
The exception thought police would have you prepend an object count, taking the curious position that external data structures should be designed to suit the coder's phobias, and overlooking that you may not know it in advance, or may need to change your mind, or may need to exit prematurely; or would have you write a null as an end-of-stream marker, overlooking that it prevents the use of null for any other purpose; and in both cases overlooking the fact that the API is already designed to throw EOFException, and already works the way it already works, so you already have to code accordingly.
The code that I'm proposing let you to serialize and deserialize multiple objects really easily without having any problems and avoiding the awful (in my opinion) while true:
public class EntityClass implements Serializable{
private int intVal;
private String stringVal;
public EntityClass(int intVal, String stringVal) {
this.intVal = intVal;
this.stringVal = stringVal;
}
#Override
public String toString() {
return "EntityClass{" +
"intVal=" + intVal +
", stringVal='" + stringVal + '\'' +
'}';
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
EntityClass a = new EntityClass(1, "1");
EntityClass b = new EntityClass(2, "2");
EntityClass c = new EntityClass(3, "3");
ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream("out"));
stream.writeObject(a);
stream.writeObject(b);
stream.writeObject(c);
stream.close();
ObjectInputStream streamRead = new ObjectInputStream(new FileInputStream("out"));
EntityClass[] entities = new EntityClass[3];
int cont = 0;
try {
while (streamRead.available() >= 0) {
entities[cont] = (EntityClass) streamRead.readObject();
System.out.println(entities[cont]);
cont++;
}
} catch (EOFException exp) {
} finally {
streamRead.close();
}
}
}
Hi I have an issue when trying to append new objects to the existing file..
Once the android app has been lunched again I want to get the existing file and add a new objects then read the objects from the existing file ... Actually, when I'm trying to read the object, the code will read only the first objects .. You can find below the code .. Could you please help ? Thanks
using the following method to write an objects :
public void saveObject(Person p, File f){
try
{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f, true));
oos.writeObject(p);
oos.reset();
oos.flush();
oos.close();
}
catch(Exception ex)
{
Log.v("Serialization Save Error : ",ex.getMessage());
ex.printStackTrace();
}
}
Using the following method to read an objects :
public Object loadSerializedObject(File f)
{
try {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f));
try{
Object loadedObj = null;
while ((loadedObj = ois.readObject()) != null) {
Log.w(this.getClass().getName(), "ReadingObjects") ;
}
return objects;
}finally{
ois.close();
}
} catch (StreamCorruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
Unfortunately you can't create a new ObjectOutputStream every time you want to append to the stream and then read everything back with a single stream. The constructor adds headers to the underlying stream before you start writing objects. You are probably seeing the java.io.StreamCorruptedException: invalid type code: AC exception, that's because the first header is 0xAC.
I don't know how many objects you are dealing with, but one option might be to read all your objects and then rewriting them all using a single ObjectOutputStream. That can get pricy if there are lots of objects. Alternatively, you might want to consider managing the serialization yourself manually through Externalizable. It can get painful though.
I wrote this function which will attempt to store the map but its not working I think? I am using netbeans and each time i go to the directory of project in the java src i can't find the created file or anywhere else in the project. The map is surely valid because output comes out perfect when am not dealing with storage. btw I do implement seriliazable :)
Note: the map is of type TreeMap
public boolean storeMap(TreeMap<DateTime, Integer> map){
try{
f_out = new FileOutputStream("mapObject.data");
obj_out = new ObjectOutputStream (f_out);
obj_out.writeObject(map);
return true;
}catch(IOException ioe){
System.err.print(ioe);
return false;
}
}
is there a reason why the output file is not generated?
Thanks
I suggest to use absolute path, that is something like
f_out = new FileOutputStream("/home/username/mapObject.data");
or on windows
f_out = new FileOutputStream("c:\\work\\mapObject.data");
If there was no exception thrown (System.err.print(ioe); this line did not print anything) then the file was created somewhere.
SERIALIZE A HASHMAP:
This code is working fine , I have implemented and used in my app. Plz make ur functions accordingly for saving map and retrieving map.
Imp thing is, you need to make confirm that the objects you are putting as value in map must be serializable , means they should implement serailizbele interface. ex.
Map<.String,String> hashmap=new HashMap<.String,String>().. here in this line ...map and string both are implictly serializable , so we dont need to implement serializble for these explicitly but if you put your own object that must be serializable.
public static void main(String arr[])
{
Map<String,String> hashmap=new HashMap<String,String>();
hashmap.put("key1","value1");
hashmap.put("key2","value2");
hashmap.put("key3","value3");
hashmap.put("key4","value4");
FileOutputStream fos;
try {
fos = new FileOutputStream("c://list.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(hashmap);
oos.close();
FileInputStream fis = new FileInputStream("c://list.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
Map<String,String> anotherList = (Map<String,String>) ois.readObject();
ois.close();
System.out.println(anotherList);
} catch (FileNotFoundException e) {e.printStackTrace();
} catch (IOException e) {e.printStackTrace();
} catch (ClassNotFoundException e) {e.printStackTrace();
}
}
Try to call fulsh() method for outputStreams.
obj_out.flush();
f_out.flush();
and close them in finally statment.