Appending objects to a binary file - java

Supose you have the following method:
public static void writeToBinary(Object obj, String filename)
{
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream(filename));
oos.writeObject(obj);
} catch (Exception e) {
e.printStackTrace();
} finally{
try{
if (oos != null) oos.close ();
}catch (Exception e){
e.printStackTrace();
}
}
}
As you can see, the method writes an object to a binary file.
But now you want to rewrite the same method to allow appending objects to the same file.
Ok, you look at the java documentation and you see that you have to add a parameter with value true to the FileOutputStream:
oos = new ObjectOutputStream(new FileOutputStream(filename, true));
You compile but, whoops!, it seems that it continues overriding the file.
Well, the problems begin. After searching in google you read that you have to use the SAME ObjectOutputStream to append objects to the same file. You want to have a function that every time you call it, it appends an object. I.e. :
writeToBinary("a", filename);
writeToBinary("b", filename);
But as I said before, you have to use the same ObjectOutputStream.
Solution 1:
ObjectOutputStream out = getOutputStream (filename);
writeToBinary("a", out);
writeToBinary("b", out);
writeToBinary("c", out);
out.close ();
This is very ugly because I want to hide the usage of streams.
Is there any other solution?
EDIT: The method is static. It is inside an utility class where all methods are static.
EDIT2: SOLVED! Appending to an ObjectOutputStream. See accepted answer to my question.
Thanks.

Solved.
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
public class Test{
private static String filename = "test";
public static void main(String[] args) {
writeToBinary (filename, "a", true);
writeToBinary (filename, "b", true);
writeToBinary (filename, "c", true);
readFromBinaryFile (filename);
}
public static void writeToBinary (String filename, Object obj, boolean append){
File file = new File (filename);
ObjectOutputStream out = null;
try{
if (!file.exists () || !append) out = new ObjectOutputStream (new FileOutputStream (filename));
else out = new AppendableObjectOutputStream (new FileOutputStream (filename, append));
out.writeObject(obj);
out.flush ();
}catch (Exception e){
e.printStackTrace ();
}finally{
try{
if (out != null) out.close ();
}catch (Exception e){
e.printStackTrace ();
}
}
}
public static void readFromBinaryFile (String filename){
File file = new File (filename);
if (file.exists ()){
ObjectInputStream ois = null;
try{
ois = new ObjectInputStream (new FileInputStream (filename));
while (true){
String s = (String)ois.readObject ();
System.out.println (s);
}
}catch (EOFException e){
}catch (Exception e){
e.printStackTrace ();
}finally{
try{
if (ois != null) ois.close();
}catch (IOException e){
e.printStackTrace ();
}
}
}
}
private static class AppendableObjectOutputStream extends ObjectOutputStream {
public AppendableObjectOutputStream(OutputStream out) throws IOException {
super(out);
}
#Override
protected void writeStreamHeader() throws IOException {}
}
}

oos = new ObjectOutputStream(new FileOutputStream(filename, true)); You
compile but, whoops!, it seems that it
continues overriding the file.
That does not make sense. The FileOutputStream is a streams that appends to the existing file, so it will not overwite the file. Check it.
The problem is that a stream cannot be closed and reopened to serialize several objects. Run the following and compare the resulting files to check it.
public class XX {
public static void writeToBinary(Object obj, String filename) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filename,true));
oos.writeObject(obj);
oos.close();
}
public static void writeToBinary2(Object obj1, Object obj2,String filename) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filename,true));
oos.writeObject(obj1);
oos.writeObject(obj2);
oos.close();
}
public static void main(String[] args) throws Exception {
String s1= "hi, just trying";
String s2= "bye bye cruel world";
String filename = "/temp/f.dat";
String filename2 = filename + ".2" ;
writeToBinary(s1, filename);
writeToBinary(s2, filename);
writeToBinary2(s1, s2,filename2);
ObjectInputStream fin = new ObjectInputStream(new FileInputStream(filename)); // oops... works with filename2
Object x1 = fin.readObject();
Object x2 = fin.readObject();
System.out.println(x1);
System.out.println(x2);
}
}

Write a helper class. In constructor it will instantiate an output stream for a particular file name. Then using some append() or writeToBinary() method it will append the data. on method close() there will be flush() and close() calls on the stream.
BinaryWriteHelper helper = new BinaryWriteHelper("test.dat");
helper.writeToBinary("1");
helper.writeToBinary(2);
helper.close();
in BinaryWriteHelper :
public BinaryWriteHelper(String filename) {
this.stream = new ObjectOutputStream(new FileOutputStream(filename));
}
public close() {
// the cleanup here
}

Try this approach:
Write the object to a ByteArrayOutputStream.
Append the the size and contents of the ByteArrayOutputStream to a RandomAccessFile.
To load an object from the file, read the bytes that represent an Object into a ByteArrayInputStream and initialize an ObjectInputStream on this. The size field that was prepends each object byte sequence will come handy here.

Related

Why can't I read an object from a binary file using ObjectInputStream wrapped with a FIleInputStream?

public class JavaApplication {
public static void main(String[] args) throws IOException{
URL u = new URL("https://www.javatpoint.com/java-string-valueof");
byte[]bytes= u.openStream().readAllBytes();
ObjectOutputStream output= new ObjectOutputStream(
new FileOutputStream("binary.dat"));
output.write(bytes);
output.close();
//Scanning the URL works just not the try and catch block
try{
ObjectInputStream input = new ObjectInputStream(new FileInputStream
("binary.dat"));
byte[]byte1= (byte[])input.readObject();
String any;
for(int i=0; i<byte1.length; i++){
any=String.valueOf(byte1[i]);
System.out.println(any);
}
input.close();
}
catch(Exception e){
System.out.println(e);}
}
}
I used a new byte array to read the object from file, use String.valueOf() to obtain the String value of the byte, then a for-loop to iterate the String. What am I doing wrong?
As the first commenter said, your main problem was not using writeObject. The only other problem is the way you turn the bytes into text. Your code will result in the 'ascii' code of the character being printed instead of the character itself. In fact you can simplify the output code as follows:
import java.io.*;
import java.net.*;
public class JavaApplication {
public static void main(String[] args) throws IOException {
URL u = new URL("https://www.javatpoint.com/java-string-valueof");
byte[] bytes = u.openStream().readAllBytes();
ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("binary.dat"));
output.writeObject(bytes);
output.close();
try {
ObjectInputStream input = new ObjectInputStream(new FileInputStream("binary.dat"));
byte[] byte1 = (byte[]) input.readObject();
System.out.println(new String(byte1));
input.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
To solve your problem, I prefer you :
Add implementation of URLConnection for avoidance from Http Status 403 / Forbidden. Reference
use ByteArrayOutputStream to write the byte and save it into file using ObjectOutputStream
if you read with readObject() you must write with writeObject()
public class JavaApplication {
public static void main(String[] args) throws IOException, ClassNotFoundException {
URL u = new URL("https://www.javatpoint.com/java-string-valueof");
URLConnection uc = u.openConnection();
uc.addRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
InputStream is = null;
try {
is = uc.getInputStream();
byte[] byteChunk = new byte[4096]; // Or whatever size you want to read in at a time.
int n;
while ((n = is.read(byteChunk)) > 0) {
baos.write(byteChunk, 0, n);
}
} catch (IOException e) {
System.err.printf("Failed while reading bytes from %s: %s", u.toExternalForm(), e.getMessage());
} finally {
if (is != null) {
is.close();
}
}
byte[] bytes = baos.toByteArray();
ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("binary.dat"));
output.writeObject(bytes);
output.close();
//Scanning the URL works just not the try and catch block
try {
ObjectInputStream input = new ObjectInputStream(new FileInputStream("binary.dat"));
byte[] byte1 = (byte[]) input.readObject();
String any;
for (int i = 0; i < byte1.length; i++) {
any = String.valueOf(byte1[i]);
System.out.println(any);
}
input.close();
} catch (IOException e) {
System.out.println(e);
}
}
}

How to appends objects in byte stream using ObjectOutputStream

I want to append multiple object at the end to the same binary file using ObjectOutputStream
But when I run the following code more than one time I get the exception
java.io.StreamCorruptedException: invalid type code: AC
The question is
Is there any headers things that I should know to APPEND OBJECTS at the end of the file in java?
package sourcepackage;
import sourcepackage.persons.Person;
import sourcepackage.persons.Student;
import java.io.*;
public class MainClass {
public static void main(String[] args) {
Person mahmoud_kanbar = new Student(21, 224466, "Mahmoud Kanbar", "ITE");
try {
FileOutputStream out = new FileOutputStream("Hello.dat", true);
ObjectOutputStream objectOut = new ObjectOutputStream(out);
objectOut.writeObject(mahmoud_kanbar);
objectOut.close();
out.close();
FileInputStream in = new FileInputStream("Hello.dat");
ObjectInputStream objectIn = new ObjectInputStream(in);
while (in.available() != 0) {
Person hi = (Person) objectIn.readObject();
hi.printInfo();
}
objectIn.close();
in.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
I was searching for decades about a solution to this problem and I couldn't find anything
I want to append objects just like the c++ do
You can append objects to the same ObjectOutputStream with writeObject() method. When reading, they are read in the same order they were written. Also, you may be getting that error because your stream is buffered and not written. You should use flush() method to make sure the buffer has been written to the file.
Let's write two objects to the same file and read them:
Person mahmoud_kanbar = new Student(21, 224466, "Mahmoud Kanbar", "ITE");
Person omid = new Student(18, 200000, "Omid Nejadabbasi", "ITE");
try {
FileOutputStream out = new FileOutputStream("Hello.dat", true);
ObjectOutputStream objectOut = new ObjectOutputStream(out);
objectOut.writeObject(mahmoud_kanbar);
objectOut.writeObject(omid);
objectOut.flush();
objectOut.close();
out.close();
FileInputStream in = new FileInputStream("Hello.dat");
ObjectInputStream objectIn = new ObjectInputStream(in);
Person newPerson= (Person) objectIn.readObject();
newPerson.printInfo();
newPerson= (Person) objectIn.readObject();
newPerson.printInfo();
objectIn.close();
in.close();
} catch (Exception e) {
System.out.println(e);
}
readObject() deserializes the next Object serialized into the stream.

Java: PrintWriter not writing in file

I ran over some problem with PrintWriter. I wrote some code that simply takes some input from a file and outputs it to another one.
Though a file is created, the file remains empty. The wanted input can be easily printed out in the console, which means the FileInputStream is working correctly.
Why is PrintWriter not printing anything?
public static void writeInFile(File in, File out) throws FileNotFoundException {
PrintWriter outputStream = null
Scanner scanner = new Scanner(new FileInputStream(in));
outputStream = new PrintWriter(new FileOutputStream(out));
outputStream.print("test");
while(scanner.hasNext()) {
outputStream.print(scanner.nextLine() + "\n");
}
scanner.close();
}
Make sure you always close your OutputStreams:
while(scanner.hasNext()) {
String s = scanner.nextLine();
outputStream.print(s+"\n");
System.out.println("Test "+s); //d.h. das Problem liegt am outputstream
}
outputStream.close();
scanner.close();
Edit: When you close the outputStream it calls flush automatically, which writes the buffer to the file. Without closing it the buffer may never be emptied/written to the file, as was the case here.
Also see this answer.
When dealing with IO which requires cleanup, I prefer to use auto resource cleanup. This is all you need at the most basic level:
public static void writeInToOut(InputStream in, OutputStream out) {
try(PrintWriter outputStream = new PrintWriter(out);
Scanner scanner = new Scanner(in)) {
while(scanner.hasNext()) {
outputStream.print(scanner.nextLine()+"\n");
}
}
}
You can now overload this function in several ways:
public static void writeInToOut(File file, OutputStream out) {
try (InputStream in = new FileInputStream(file)) {
writeInToOut(in, out);
} catch (IOException e) {
Logger.getAnonymousLogger().log(Level.WARNING, "IOError", e);
}
}
public static void writeInToOut(File inFile, File outFile) {
try (InputStream in = new FileInputStream(inFile);
OutputStream out = new FileOutputStream(outFile)) {
writeInToOut(in, out);
} catch (IOException e) {
Logger.getAnonymousLogger().log(Level.WARNING, "IOError", e);
}
}
public static void writeStdInToFile(File file) {
try (OutputStream out = new FileOutputStream(file)) {
writeInToOut(System.in, out);
} catch (IOException e) {
Logger.getAnonymousLogger().log(Level.WARNING, "IOError", e);
}
}

How to (de)serialize correctly to a byte-array using a ObjectOutputStream & ObjectInputStream?

I am aware that an ObjectOutputStream/ObjectInputStream uses headers and this is not really a proper use-case. But anyway I need to wrap some data into it using the interfaces DataInput and DataOutput.
import java.util.*;
import java.lang.*;
import java.io.*;
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
byte[] array = serialize("test");
String deserialized = deserialize(array);
System.out.println(deserialized);
}
private static byte[] serialize(String test) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeUTF(test);
byteArrayOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
return byteArrayOutputStream.toByteArray();
}
private static String deserialize(byte[] array) {
String temp = null;
try {
ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(array));
temp = objectInputStream.readUTF();
objectInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
return temp;
}
}
I don't really get how to get that working. Am I right, that the problem are those headers currently?
You should call objectOutputStream.flush(); before closing byteArrayOutputStream.
ObjectOutputStream have its internal buffer so you got only beginning of string in your byte array.

How to write and read java serialized objects into a file

I am going to write multiple objects to a file and then retrieve them in another part of my code. My code has no error, but it is not working properly. Could you please help me find what is wrong about my code.
I read different codes from different websites, but none of them worked for me!
Here is my code to write my objects to a file:
MyClassList is an arraylist which includes objects of my class (which must be written to a file).
for (int cnt = 0; cnt < MyClassList.size(); cnt++) {
FileOutputStream fout = new FileOutputStream("G:\\address.ser", true);
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject(MyClassList.get(cnt));
}
I added "true" to the constructor of the outputstream, because I want to add each object to end of the file. Is that correct?
And here is my code to read the objects from the file:
try {
streamIn = new FileInputStream("G:\\address.ser");
ObjectInputStream objectinputstream = new ObjectInputStream(streamIn);
MyClass readCase = (MyClass) objectinputstream.readObject();
recordList.add(readCase);
System.out.println(recordList.get(i));
} catch (Exception e) {
e.printStackTrace();
}
It finally prints out just one object. Now, I don't know if I am not writing correctly or reading correctly!
Why not serialize the whole list at once?
FileOutputStream fout = new FileOutputStream("G:\\address.ser");
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject(MyClassList);
Assuming, of course, that MyClassList is an ArrayList or LinkedList, or another Serializable collection.
In the case of reading it back, in your code you ready only one item, there is no loop to gather all the item written.
As others suggested, you can serialize and deserialize the whole list at once, which is simpler and seems to comply perfectly with what you intend to do.
In that case the serialization code becomes
ObjectOutputStream oos = null;
FileOutputStream fout = null;
try{
fout = new FileOutputStream("G:\\address.ser", true);
oos = new ObjectOutputStream(fout);
oos.writeObject(myClassList);
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if(oos != null){
oos.close();
}
}
And deserialization becomes (assuming that myClassList is a list and hoping you will use generics):
ObjectInputStream objectinputstream = null;
try {
FileInputStream streamIn = new FileInputStream("G:\\address.ser");
objectinputstream = new ObjectInputStream(streamIn);
List<MyClass> readCase = (List<MyClass>) objectinputstream.readObject();
recordList.add(readCase);
System.out.println(recordList.get(i));
} catch (Exception e) {
e.printStackTrace();
} finally {
if(objectinputstream != null){
objectinputstream .close();
}
}
You can also deserialize several objects from a file, as you intended to:
ObjectInputStream objectinputstream = null;
try {
streamIn = new FileInputStream("G:\\address.ser");
objectinputstream = new ObjectInputStream(streamIn);
MyClass readCase = null;
do {
readCase = (MyClass) objectinputstream.readObject();
if(readCase != null){
recordList.add(readCase);
}
} while (readCase != null)
System.out.println(recordList.get(i));
} catch (Exception e) {
e.printStackTrace();
} finally {
if(objectinputstream != null){
objectinputstream .close();
}
}
Please do not forget to close stream objects in a finally clause (note: it can throw exception).
EDIT
As suggested in the comments, it should be preferable to use try with resources and the code should get quite simpler.
Here is the list serialization :
try(
FileOutputStream fout = new FileOutputStream("G:\\address.ser", true);
ObjectOutputStream oos = new ObjectOutputStream(fout);
){
oos.writeObject(myClassList);
} catch (Exception ex) {
ex.printStackTrace();
}
Simple program to write objects to file and read objects from file.
package program;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class TempList {
public static void main(String[] args) throws Exception {
Counter counter = new Counter(10);
File f = new File("MyFile.txt");
FileOutputStream fos = new FileOutputStream(f);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(counter);
oos.close();
FileInputStream fis = new FileInputStream(f);
ObjectInputStream ois = new ObjectInputStream(fis);
Counter newCounter = (Counter) ois.readObject();
System.out.println(newCounter.count);
ois.close();
}
}
class Counter implements Serializable {
private static final long serialVersionUID = -628789568975888036 L;
int count;
Counter(int count) {
this.count = count;
}
}
After running the program the output in your console window will be 10 and you can find the file inside Test folder by clicking on the icon show in below image.
I think you have to write each object to an own File or you have to split the one when reading it.
You may also try to serialize your list and retrieve that when deserializing.
if you serialize the whole list you also have to de-serialize the file into a list when you read it back. This means that you will inevitably load in memory a big file. It can be expensive. If you have a big file, and need to chunk it line by line (-> object by object) just proceed with your initial idea.
Serialization:
LinkedList<YourObject> listOfObjects = <something>;
try {
FileOutputStream file = new FileOutputStream(<filePath>);
ObjectOutputStream writer = new ObjectOutputStream(file);
for (YourObject obj : listOfObjects) {
writer.writeObject(obj);
}
writer.close();
file.close();
} catch (Exception ex) {
System.err.println("failed to write " + filePath + ", "+ ex);
}
De-serialization:
try {
FileInputStream file = new FileInputStream(<filePath>);
ObjectInputStream reader = new ObjectInputStream(file);
while (true) {
try {
YourObject obj = (YourObject)reader.readObject();
System.out.println(obj)
} catch (Exception ex) {
System.err.println("end of reader file ");
break;
}
}
} catch (Exception ex) {
System.err.println("failed to read " + filePath + ", "+ ex);
}

Categories

Resources