0

Here's my code:

 try {

                Uri uri = Uri.parse("file:///storage/emulated/0/Download/information.csv");
                File file = new File(uri.getPath());
                //Read the file
                BufferedReader br = new BufferedReader(new FileReader(file));
                String line;
                boolean firstLine = true;

                while ((line = br.readLine()) != null) {
                    System.out.println("Print the contents from the file :" + line);
                    if (firstLine) {
                        firstLine = false;
                        continue;
                    } else {

                            //deserialize the string to Object
                            td = TransferData.fromString(line); //Where td is an object 

                            //deserialize the string to Object
                            System.out.println("deserialized: " + td);



               }

However, I get an exception on this line:

td = TransferData.fromString(line);

and from my fromString function:

/** Read the object from Base64 string. */
    public static TransferData fromString( String s ) throws IOException, ClassNotFoundException     {
        byte [] data = Base64.decode(s, Base64.DEFAULT);
        ObjectInputStream ois = new ObjectInputStream(
                new ByteArrayInputStream(  data ) );
        Object o  = ois.readObject();
        ois.close();
        return (TransferData)o;
    }

The exception is StreamCorruptedException but I'm not sure why that is. I want to be able to read in a string and deserialize the string.

EDIT:

  /** Write the object to a Base64 string. */
    public static String toString(Serializable o) throws IOException {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(output);
        oos.writeObject(o);
        oos.close();
        return new String(Base64.encode(output.toByteArray(), Base64.DEFAULT));
    }



//SerialVersionID
  private static final int serialVersionUID = 10032014;
Kala J
  • 2,040
  • 4
  • 45
  • 85
  • Where is your `ObjectOutputStream`? Which object are you trying to deserialize? Are you sure that the [`serialVersionUID`](http://stackoverflow.com/q/285793/3735079) is correctly configured? – Narmer Oct 20 '14 at 13:08
  • Remeber that, as per the Javadoc, _An `ObjectInputStream` deserializes primitive data and objects previously written using an `ObjectOutputStream`._ If your goal is to read a string from a file `ObjectInputStream` is [not what you need](http://stackoverflow.com/questions/326390/how-to-create-a-java-string-from-the-contents-of-a-file). – Narmer Oct 20 '14 at 13:12
  • Well here is the thing. I have two devices, one device takes an object and converts it to a string. Then saves the string to a file. The other devices reads the string in that file and deserializes it. – Kala J Oct 20 '14 at 13:37
  • My objectOutputStream is in my toString method. Where would I need an output stream here? – Kala J Oct 20 '14 at 13:39
  • The StreamCorruptedException is "Thrown when control information that was read from an object stream violates internal consistency checks." That means your code that serializes the object to the file is not correct. – Breandán Dalton Oct 20 '14 at 14:09

1 Answers1

3

I can see some flaws in your code:

  1. You are creating a new ObjectInputStream each time you read a new line (which is probably causing the StreamCorruptedException)
  2. If you are reading the file via BufferedReader you don't need an ObjectInputStream and viceversa.
  3. I can't understand, why you are doing a Base64.decode of the string?
  4. You must assure that the serialVersionUID is coherent.

If I understood well you want to serialize an object to a file and then deserialize it. First of all you should have an entity (your object) which implements the Serializable interface:

public class Foo implements Serializable{
    static final long serialVersionUID = 42L;
    //class code...
}

Now you can safely save your object (or a list of it) to a file:

FileOutputStream fos = new FileOutputStream("myFoo.tmp");
ObjectOutputStream oos = new ObjectOutputStream(fos);

Foo foo = new Foo();
//Fill the object.

oos.writeObject(foo);

If you need to read that file you can now do:

FileInputStream fis = new FileInputStream("myFoo.tmp");
ObjectInputStream ois = new ObjectInputStream(fis);

Foo mySavedFoo = (Foo) ois.readObject();

If you need to save a list of objects you can use the ArrayList implementation of List which implements Serializable:

FileOutputStream fos = new FileOutputStream("myFoos.tmp");
ObjectOutputStream oos = new ObjectOutputStream(fos);

List<Foo> foos = new ArrayList<Foo>();
//Fill the list.

oos.writeObject(foos);

//...

FileInputStream fis = new FileInputStream("myFoos.tmp");
ObjectInputStream ois = new ObjectInputStream(fis);

ArrayList<Foo> mySavedFoo = (ArrayList<Foo>) ois.readObject();

ADDENDUM

A StreamCorruptedException is Thrown when control information that was read from an object stream violates internal consistency checks.

When an object is written on a file using a ObjectOutputStream, it's added of a properly formatted header used when the object is deserialized. If such header isn't consistent you have a violation of internal consistency checks.

When you are reading, line by line (line = br.readLine()), your file, you are removing such header and thus your ObjectInputStream can't properly read the object you saved. Furthermore you are decoding a Base64, scrambling even more the data read. Add that for every line you create a new ObjectInputStream and StreamCorruptedException appears.


EDIT

From your edit I can understand better what is your problem.

public static String toString(Serializable o) throws IOException {
    //                   what is this? ^
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(output);
    oos.writeObject(o); //Here you are saving a Serializable object to... what? Which file?
    oos.close();
    return new String(Base64.encode(output.toByteArray(), Base64.DEFAULT));
}

Just like my example before, you are storing a Serializable object via ObjectOutputStream (where BTW?), but Serializable is only an interface. It would be better if you used the class implementing it. Following my example it would become:

public static String toString(Foo o) throws IOException { //...

The Base64.encode is done AFTER the object is saved to the file!! There is no "encryption"! Also the encoding is done to the output object which is ByteArrayOutputStream and nothing has to do with the real data stored in o.

Community
  • 1
  • 1
Narmer
  • 1,414
  • 7
  • 16
  • Nice answer, Narmer. +1 – Breandán Dalton Oct 20 '14 at 14:05
  • Side thought, would it change anything if I am encrypting (on device 1) and decrypting (on devic 2) the string inside the file? Also when you say file header.. do you mean that the file header data has to be the same? edit: I edited my post to show my toString method. – Kala J Oct 20 '14 at 14:14
  • The encryption of data should be done before the data is stored and the decryption after it is retrieved. But I can't quite understand what you wwant to do... The header is internal, you should not modify nor create it. – Narmer Oct 20 '14 at 14:17
  • the file header would be the same but I would not want to turn it into an object. Btw, I updated my post to reveal my serialversionUID. Does it have to be long? – Kala J Oct 20 '14 at 14:19
  • Mmmh... You are mixing things. Forget for a second of the header, it complicates things and it's not important now. You have to understand what comes first: serialization. What are you passing in `oos.writeObject(o);`? What's `o` (instance)? – Narmer Oct 20 '14 at 14:26
  • @Narmer, serializedInfo = TransferData.toString(testSerialize); TransferData testSerialize = new TransferData(patInfo.getID(), patInfo.getDate(), ...); – Kala J Oct 20 '14 at 14:37
  • Right now, let's forget encryption and focus on the serialize/deserialize. The encryption works for me. It's just the deserialize doesn't. – Kala J Oct 20 '14 at 14:38
  • Ok, follow exactly what I wrote, just use `TransferData` instead of `Foo`. That's your entity object. Also, your encryption is broken (see my edit) and you are not providing a file to store your object. – Narmer Oct 20 '14 at 14:40
  • Also, I wouldn't use the `toString` method of your entity to serialize the object. Use instead something like `DataSerializer.serialize` (you have to create `DataSerializer`) – Narmer Oct 20 '14 at 14:44
  • Without changing the toString and FromString methods, how can I fix this issue while reading in a file? – Kala J Oct 20 '14 at 15:40
  • You can't. You have to modify them, at least the `FromString` method, removing the decoding, removing the `BufferedReader` (using directly the `File` object) and reading a `String` insted of an object. And _OBVIOUSLY_ you have to create the file in the `toString` method – Narmer Oct 20 '14 at 15:43
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/63350/discussion-between-kala-j-and-narmer). – Kala J Oct 20 '14 at 15:45