javaandroidobjectinputstreameofexception

ObjectInputStream returning EOFException when reading List of Object


Im returning a list of all the objects stored in some temporary files in my Android project. When the list its appended the file its deleted.

    public static <T> List<T> fileToLogList(Context context) {
        String path = context.getFilesDir()
                .getAbsolutePath();
        List<T> list = new ArrayList<>();
        FileInputStream fis;
        try {
            File directory = new File(path);
            File[] files = directory.listFiles();
            for (File file : files) {
                fis = new FileInputStream(file);
                ObjectInputStream ois = new ObjectInputStream(fis);
                list.addAll((List<T>) ois.readObject());
                ois.close();
                fis.close();
                context.deleteFile(file.getName());
            }
        } catch (FileNotFoundException e) {
            return new ArrayList<>();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        return list;
    }

The problem is that sometimes ois.readObject() will return a EOFException. I dont understand the accepted answer of the following question. I have tried the second answer and it also returns an exception.

E/AndroidRuntime: FATAL EXCEPTION: Timer-1
    Process: com.example.application, PID: 774
    java.lang.RuntimeException: java.io.EOFException
        at com.example.application.utils.Utils.fileToLogList(Utils.java:172)
        at com.example.application.logging.LogService$2.run(LogService.java:31)
        at java.util.TimerThread.mainLoop(Timer.java:562)
        at java.util.TimerThread.run(Timer.java:512)
     Caused by: java.io.EOFException
        at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2751)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1378)
        at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2114)
        at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2038)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1899)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1412)
        at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2114)
        at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2038)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1899)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1412)
        at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2114)
        at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2038)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1899)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1412)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:427)
        at java.util.concurrent.CopyOnWriteArrayList.readObject(CopyOnWriteArrayList.java:931)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1066)
        at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2013)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1899)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1412)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:427)
        at com.example.application.utils.Utils.fileToLogList(Utils.java:164)
        at com.example.application.logging.LogService$2.run(LogService.java:31) 
        at java.util.TimerThread.mainLoop(Timer.java:562) 
        at java.util.TimerThread.run(Timer.java:512) 

Lastly this is my method to write into the files:

    public static <T> void logListIntoFile(List<T> output, Context context) {
        FileOutputStream fos;
        try {
            // writes into a file named YYYY-MM-DD_HH:MM
            fos = context.openFileOutput(getCurrentDateMinutes() + ".tmp", Context.MODE_PRIVATE);
            ObjectOutputStream os = new ObjectOutputStream(fos);
            os.writeObject(output);
            os.close();
            fos.close();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

Solution

  • Basically - EOF exception might be thrown in two situations,

    If you're leverage reading from file on EOF exception then you won't be able determine which one is the actual source of the problem. Do you need to to detect this difference? If not - base reading on EOF exception

    What the author of mentioned answer suggested (at least I understand it this way), to use some RandomAccessFile approach, in which apart from the actual list of objects you would store an integer as first object which will tell you how many files are there.

    Have you considered if aren't there a situation in which those reads and writes are called simultaneously? If you're trying to read a file in between some different is writing to it, such a situation may happen.

    Personally I'd try to add some synchronization, to postpone writing until reading is finished and then see what is gonna happen because I believe this is the root cause of the problem.