Writing a method to read a binary file - java

I want to write a method that reads an object from a binary file but I want to generalize it using generics.
I have this code:
#SuppressWarnings ("unchecked")
public static <T> T readFromBinaryFile (String filename){
T obj = null;
if (FileUtils.existsFile (filename)){
ObjectInputStream ois = null;
try{
ois = new ObjectInputStream (new FileInputStream (filename));
obj = (T)ois.readObject ();
}catch (IOException e){
Debug.out (e);
}catch (ClassNotFoundException e){
Debug.out (e);
}finally{
try{
if (ois != null) ois.close();
}catch (IOException e){
Debug.out (e);
}
}
}
return obj;
}
When I execute it I get a ClassCastException. I don't know anything about templates in java so any information will be apreciated. I've read something related to erasure, compile-time and execution-time but I don't understand very well why I get this ClassCastException.
Thanks.
EDIT: I call the method like this:
FileUtils.readFromBinaryFile (filename); (Without "")

Are there templates in Java? Just use Object instead of T. In Java everything derives from Object at the base, so you don't want T obj but Object obj.

A ClassCastException means the type you read didn't match the type you were expecting (and cast to) I suggest you see which object you are read in a debugger (or a log message) and compare it with what you are expecting.

You're calling your method wrong.
Just do it this way:
FileUtils.readFromBinaryFile (filename);
What you're calling is so-called generic method.
"We don't have to pass an actual type argument to a generic method. The compiler infers the type argument for us, based on the types of the actual arguments. It will generally infer the most specific type argument that will make the call type-correct." source
EDIT:
I've tried your example and it works (I had actually comment some lines)
private static String filename = "number.serialized";
public static void main(String[] args) {
Double d = 3.14;
writeToBinary(d, filename);
Double readD = readFromBinaryFile(filename);
System.out.println(readD);
}
#SuppressWarnings ("unchecked")
public static <T> T readFromBinaryFile(String filename) {
T obj = null;
File file = new File(filename);
if (file.exists()) {
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream(filename));
obj = (T)ois.readObject();
} catch (IOException e) {
} catch (ClassNotFoundException e) {
} finally {
try {
if (ois != null)
ois.close();
} catch (IOException e) {
}
}
}
return obj;
}
public static <T> void writeToBinary(T obj, String filename)
{
try {
FileOutputStream fis = new FileOutputStream(filename);
ObjectOutputStream oos = new ObjectOutputStream(fis);
oos.writeObject(obj);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

Related

How to retrieve object from key value database into Map, then convert back to object in Java

I am storing an object as a value in LevelDB. Both key and value must be in bytes for LevelDB.
I am receiving an object via a socket and casting it to MyObject:
MyObject myObject = (MyObject) (objectInput.readObject());
Then I am serialising my object when storing the value in LevelDB:
myLevelDb().put(bytes((publicKey)), Serializer.serialize(myObject));
The serializer code is as follows:
public static byte[] serialize(Object object) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream(bos);
out.writeObject(object);
out.flush();
byte[] yourBytes = bos.toByteArray();
return yourBytes;
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bos.close();
} catch (IOException ex) {
// ignore close exception
}
} return null;
}
Then I am trying to iterate through the LevelDB and store each object into a Map. Here is where I am trying to deserialize the bytes back into MyObject and save them to Map:
private void iterateBytes() {
DBIterator iterator = myLevelDb().iterator();
while (iterator.hasNext()) {
Map.Entry<byte[], byte[]> next = iterator.next();
String keyString = new String(next.getKey());
MyObject myObject = (MyObject) Serializer.deserialize(next.getValue());
Map<String, MyObject> myMap = new HashMap<>();
myMap().put(keyString, myObject);
}
}
However, Java will not let me cast the deserialized bytes back to MyObject after it has been deserialized using the following code:
public static Object deserialize(byte[] bytes) {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInput in = null;
try {
in = new ObjectInputStream(bis);
Object o = in.readObject();
return o;
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException ex) {
// ignore close exception
}
} return null;
}
I don't understand why I cannot convert the object back from a byte[] when I have followed the exact same method of serializing and deserializing. MyObject implements Serializable and the SUID is correct, as it works on API calls between devices. I just cannot add it to a Map as the original object, nor will Java let me cast it.
This is the line where an error is thrown, no matter where I try to cast it back to myObject:
MyObject myObject = (MyObject) Serializer.deserialize(next.getValue());
Error:
class java.lang.String cannot be cast to class myPackage.MyObject (java.lang.String is in module java.base of loader 'bootstrap';
This was solved by casting the generic Object object to MyObject (user defined class object) at serialization and also casting it at deserialization.
Here is the code at serialization:
public static byte[] serialize(MyObject myObject) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream(bos);
out.writeObject(myObject);
out.flush();
byte[] yourBytes = bos.toByteArray();
return yourBytes;
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bos.close();
} catch (IOException ex) {
// ignore close exception
}
} return null;
}
And here is the code for deserializaion.
public static MyObject deserializeNodeClient(byte[] bytes) {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInput in = null;
try {
in = new ObjectInputStream(bis);
MyObject myObject = (MyObject) in.readObject();
return myObject;
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException ex) {
// ignore close exception
}
} return null;
}
So although the original OP code works fine is some cases, the original object cannot be derived by using a generic Object object serialization, then casting the output.

Appendable Binary File

I'm working on appending objects to a binary file. My file is:
File f=new File("person.dat");
I'm getting an error (java.io.StreamCorruptedException: invalid stream header: 79737200) when I attempt to open the binary file. As far as I can tell the program writes the data just fine, but as soon as I try reading from it, I get the above error. Any help is appreciated!
My Code to write:
AppendObjectOutputStream out = null;
try {
out = new AppendObjectOutputStream(new FileOutputStream(f, true));
out.writeObject(new Student(name, age));
out.flush();
}
catch (Exception ex) {
ex.printStackTrace();
}
finally {
out.close();
}
My class for making appendable:
public class AppendObjectOutputStream extends ObjectOutputStream {
public AppendObjectOutputStream(OutputStream out) throws IOException {
super(out);
}
#Override
protected void writeStreamHeader() throws IOException {
reset();
}
}
My partial code for reading and adding objects to an ArrayList:
Course course = new Course();
Student st = null;
ObjectInputStream in = null;
try {
in = new ObjectInputStream(new FileInputStream("person.dat"));
try
{
while (true)
{
st = (Student) in.readObject();
course.addAccount(st); //adds student object to an ArrayList in
//class Course
}
}
catch (EOFException ex) {
}
}
catch (Exception ex) {
ex.printStackTrace();
} finally {
in.close();
}
UPDATE:
Current code to read but its not printing anything to screen:
try(ObjectInputStream ois = new ObjectInputStream(
new BufferedInputStream(Files.newInputStream(f))))
{
while (ois.available() > 0)
{
st = (Student) ois.readObject();
studentlist.addAccount(st);
System.out.println(st.getStudentNumber());
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
This is how I write to file:
Path f = Paths.get("person.dat");
try (ObjectOutputStream oos = new ObjectOutputStream(
new BufferedOutputStream(Files.newOutputStream(f, StandardOpenOption.APPEND))))
{
oos.writeObject(new Student(name,age));
}
catch(Exception ex)
{
ex.printStackTrace();
}
Rather than trying to fix your utility classes, I suggest to use the standard classes of the NIO.2 File API.
Try something like (untested):
Path personDataFilePath = Paths.get("person.dat");
// or Java 11:
// Path personDataFilePath = Path.of("person.dat");
try (ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(Files.newOutputStream(personDataFilePath, StandardOpenOption.APPEND)))){
oos.writeObject(new Student(name,age));
} catch (IOException ex) {
// do some error handling here
}
and to read the file, something like (untested):
List<Student> students = new ArrayList<>();
try (ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(Files.newInputStream(personDataFilePath)))){
while (ois.available() > 0){
students.add((Student) ois.readObject());
}
} catch (IOException ex) {
// do some error handling here
}
I have modified the code to work around making a file "appendable". I write a single arraylist object to the file (the arraylist holds a list of student objects). When I want to add a student, I read the object (arraylist) from the file, add my new student to the arraylist and write the arraylist back to the file. It is now working and my file does not have an append format.

Appending to ObjectOutputStream [duplicate]

This question already has answers here:
Appending to an ObjectOutputStream
(6 answers)
Closed 5 years ago.
I have a program utilizing the memento design pattern and want to save the state of each object into a file using serialization and return the object back. The problem is that I get a "java.io.StreamCorruptedException: invalid type code: AC" exception due to corrupt headers. I looked at Appending to an ObjectOutputStream and tried to implement the class but still can't get the program to work properly. Multiple objects should be saved in a file and the user passes a string into a function which should match part of the object's string representation.
public class Caretaker implements Serializable {
public void addMemento(Memento m) {
try {
// write object to file
FileOutputStream fos = new FileOutputStream("ConeOutput1.txt", true);
BufferedOutputStream outputBuffer = new BufferedOutputStream(fos);
AppendableObjectOutputStream objectStream = new AppendableObjectOutputStream(outputBuffer);
objectStream.writeObject(m);
objectStream.reset();
objectStream.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public Memento getMemento(String temp) {
try {
Memento result = null;
FileInputStream fis = new FileInputStream("ConeOutput1.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
result = (Memento) ois.readObject();
while (result != null) {
Matcher m = Pattern.compile(temp).matcher(result.toString());
if (m.find()) {
return result;
}
else {
result = (Memento) ois.readObject();
}
ois.close();
}
}
catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
public class AppendableObjectOutputStream extends ObjectOutputStream {
public AppendableObjectOutputStream(OutputStream out) throws IOException {
super(out);
}
#Override
protected void writeStreamHeader() throws IOException {}
}
You should only use the appending ObjectOutputStream if the file already exists with data in it. If the file is new it needs the object stream header.

Can't read multiple objects from a file

I'm trying to put the (Lieu) objects into an ArrayList but but at the end of the code, my list is still empty. I've been looking on the net for an answer but all I find is "Write your objects in a collection then read the collection". But the file is already written and i need to find a way to put all the (Lieu) objects in a ArrayList.
Here's the writing Code (I can't modify it):
public static void main(String[] args) {
Lieu<Double, String> p1;
Lieu<Double, String> p2;
Lieu<Double, String> p3;
SegmentGeo<String> e1;
SegmentGeo<String> e2;
SegmentGeo<String> e3;
Parcelle<String> p = new Parcelle<String>();
ArrayList<Mesure<Point<Double>, String>> segs;
p1 = new Lieu<Double, String>(45.573715, -73.900295, "p1");
p2 = new Lieu<Double, String>(45.573882, -73.899748, "p2");
p3 = new Lieu<Double, String>(45.574438, -73.900099, "p3");
e1 = new SegmentGeo<String>(p1, p2, "Parcelle test");
e2 = new SegmentGeo<String>(p2, p3, "Parcelle test");
e3 = new SegmentGeo<String>(p3, p1, "Parcelle test");
segs = new ArrayList<Mesure<Point<Double>, String>>();
segs.add(e1);
segs.add(e2);
segs.add(e3);
try {
p.setMesures(segs);
} catch (TrajectoireNonValideException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ObjectOutputStream ois = null;
try {
ois = new ObjectOutputStream(new FileOutputStream("essai.txt"));
ois.writeObject(p.informationCumulee());
ois.writeObject(p1);
ois.writeObject(p2);
ois.writeObject(p3);
} catch (EOFException ex) {
System.out.println("Fin de fichier atteinte.");
} catch (FileNotFoundException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
} finally {
try {
if (ois != null) {
ois.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
And here's what I'm trying to do:
public void actionPerformed(ActionEvent arg0) {
JFileChooser chooser = new JFileChooser();
int retour = chooser.showOpenDialog(getParent());
if(retour==JFileChooser.APPROVE_OPTION){
try{
FileInputStream fis = new FileInputStream(chooser.getSelectedFile().getName());
ObjectInputStream ois = new ObjectInputStream(fis);
champNom.setText((String) ois.readObject());//that's just to display the name
while (ois.available()!=0)
{
temp = (Lieu)ois.readObject();
l.add(temp);
}
ois.close();
System.out.print(l.size());//The size is 0
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
As Joetjah says, available() doesn't work like it sounds like.
One solution that is not super elegant but works surprisingly well is to just catch the Exceptions which will be thrown when there is nothing left to read or another exception, as such:
try {
while (true)
l.add((Lieu<Double,String>)ois.readObject());
} catch (ClassNotFoundException | IOException e) {
//Expecting a EOFException here
} finally {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Whenever there's an exception is thrown when reading (and at some point there will be one!), it will stop reading.
Available doesn't do what you think it does
available() does not return the amount of data left to be read, but the amount of data that can be read without blocking (pausing to wait for more data from the file/socket/database/etc.). In some cases this may return zero while there are still bytes that should be read - the 0 means that there are 0 bytes available right now (with no blocking). This may happen for various reasons - a hard drive may be busy repositioning its magnetic reader, or a network connection may be busy, or perhaps you're waiting for a user somewhere to type something before their information may be sent. Or it may be because the file you're reading really has no additional bytes to read, because you've reached the end. Using available() you have no way of knowing whether or not you should try to read the bytes anyway.
A more correct way to use a stream to copy a file is to check the return value of read for the end-of-file value (-1):
InputStream is = // some input
OutputStream os = // some output
byte buffer = new byte[1024];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
When this code completes, you know that all the bytes really have been read and copied, because the while loop doesn't complete until read() returns -1, indicating the end of input.
Now, in your case, I'd advice to take it to some other direction, like this:
FileInputStream fis = new FileInputStream(chooser.getSelectedFile().getName());
ObjectInputStream ois = new ObjectInputStream(fis);
Object obj = ois.readObject();
while (obj != null)
{
champNom.setText((String)obj);
if (obj instanceof Lieu<Double, String>)
l.add(obj);
obj = ois.readObject();
}
ois.close();
System.out.print(l.size());

How do I store an arraylist?

I am trying to store my ArrayList between runtimes. So when I enter items into the ArrayList then close the program down and then open it back up and try to search the item I put in it will still be there.
I have tried MySQL and XML but I cannot figure it out. If you could please direct me in the direction of an easy way to store ArrayList that would be amazing.
Edit:
I am trying to serialize this ArrayList:
static ArrayList<Product> Chart=new ArrayList<Product>();
with these objects:
double Total;
String name;
double quantity;
String unit;
double ProductPrice;
Look into object serialization, it sounds like exactly what you want
What is object serialization?
This allows you to write a Java object to a file and read it back in later.
Here is an example. It also zips up the file, although you don't have to do that. You can also use the stream to write to a MYSQL blob instead of a file.
public static <T> void writeToGZIP(String filename, T obj) {
ObjectOutputStream os = null;
try {
os = new ObjectOutputStream(new GZIPOutputStream(new FileOutputStream(filename)));
os.writeObject(obj);
System.out.println("Object written to " + filename);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (os != null) { os.flush(); os.close(); }
} catch (IOException e) {
e.printStackTrace();
}
}
}
#SuppressWarnings("unchecked")
public static <T> T readFromGZIP(String filename, T obj) {
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new GZIPInputStream(new FileInputStream(filename)));
obj = (T) ois.readObject();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if( ois != null ) ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return obj;
}
ObjectOutputStream and ObjectInputStream

Categories

Resources