Search code examples
javaserializationfile-ioarraysfileinputstream

Java serialize List<object> each object holds a file in a byte array


I have an object that has a List each ObjectA has a few data members (strings and a byte[]). Along with a FileInputStream used to read a file into the byte array. I have initialized all data members in the global scope of the object so that I can recycle them to reduce the amount of object creation per function call. When I serialize the object my FileInputStream is null, as I store the file in the byte array. so I expect that the FileInputStream being null would be skipped by the serialization process. both the main object and the objects that are put in the list of the main object are implementing serializable

I'm able to serialize the object that holds the list of objects and deserialize it as long as the list is empty. When the list has at least one object in it. It's still able to serialize but when i attempt to deserialize it I get the following error.

IOException: writing aborted; java.io.NotSerializableException: java.io.FileInputStream

The variables in my object's is as followed:

public class MainObject implements Serializable{
     private String name;
     private List<ObjectA> obj;
}

public class ObjectA implements Serializable{
         private String id;
         private String name;
         private File fileStream;
         byte []data;
}

To trouble shoot this I saved the serialized object to a file and looked at it and I can see the MainObject is being saved. If I include objects into the list the objects are also being saved.

Here is the code I made for reading the files and adding them to the object.

   File[] files = new File(filePath).listFiles();
    for (File file : files) {
        if (file.isFile()) {
            System.out.println(file.getName());
            try {
                fin = new FileInputStream(filePath+file.getName());
                ois = new ObjectInputStream(fin);
                mainObjectList.add((MainObject) ois.readObject());
                ois.close();
                fin.close();
            } catch (FileNotFoundException e) {
                 System.err.println("FileNotFoundException: " + e.getMessage());
            } catch (ClassNotFoundException e) {
                 System.err.println("ClassNotFoundException: " + e.getMessage());
            } catch (IOException e) {
                 System.err.println("IOException: " + e.getMessage());
            }   
        }
    }

here is the setFile() that's in MainObject

   public void setFile(String filePath) {
        try {
            File file=null;
            fileStream = new FileInputStream(file=new File(filePath));
            data = new byte[(int)file.length()];
            fileStream.read(data,0,data.length);
            for (int X : data){
                System.out.print((char)X);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        }

    } 

Solution

  • Read the exception message. Contrary to the code you posted, you have a FileInputStream member, which is not serializable. Make it transient, or remove it, and construct it when you need it from the File.

    And contrary to your claim that 'When i serialize mainObject and save it to a file i can see its saving all the data including the list of audioClip objects', when you serialized this data you got an exception, which you have ignored.

    NB Your newly posted code:

    try {
            File file=null;
            fileStream = new FileInputStream(file=new File(filePath));
            data = new byte[(int)file.length()];
            fileStream.read(data,0,data.length);
            for (int X : data){
                System.out.print((char)X);
            }
    
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        }
    

    is very poor quality. It should have been written like this:

    try (FileInputStream fileStream = new FileInputStream(new File(filePath))) {
        data = new byte[(int)file.length()];
        int total = 0;
        int count;
        while ((count = fileStream.read(data, total, data.length-total)) > 0) {
            total += count;
        }
        for (byte X : data) {
            System.out.print((char)X);
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }catch (IOException e) {
        e.printStackTrace();
    }
    

    Note that you cannot assume either that a file fits into memory, that the size fits into an int, or that read() fills the buffer. You have to:

    • store the result of read() into a variable
    • test it for -1, indicating end of stream
    • otherwise use it as the read count, instead of the buffer size
    • repeat until end of stream.

    Note also that you don't need the File file variable at all; that the FileInputStream should always have been a local variable; and that you weren't closing it: this code does, via the try-with-resources syntax.