ObjectOutputStream.reset() leads to StreamCorruptedException



我有一个包含对文件 uri 的引用的类。这个文件应该通过网络传输,可以很大(例如视频(,我想在实例(反(序列化期间透明地执行此操作:

public class NetworkAttachment implements Serializable {
    private static final long serialVersionUID = 1L;
    private final String name;  // file name
    private final long length;  // file length
    private final long lastModified;    // last modification time
    private final String type;  // mime type
    private transient final Context context;
    private transient final Uri uri;
    [...]
    private void writeObject(ObjectOutputStream oos) throws IOException {
        oos.defaultWriteObject();   // write all non-transient fields
        ParcelFileDescriptor parcelFileDescriptor = context.getContentResolver().openFileDescriptor(uri, "r");
        if (parcelFileDescriptor != null) {
            FileInputStream fis = new FileInputStream(parcelFileDescriptor.getFileDescriptor());
            byte[] buffer = new byte[1024 * 1024];  // 1 MB temp buffer
            int len;
            while ((len = fis.read(buffer)) != -1) {
                oos.write(buffer, 0, len);
                // reset the cache else OOM exception
                oos.reset();
            }
        }
    }
}

另一方面,实例由等效代码读取:

private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
        ois.defaultReadObject();    // read all non-transient fields
        File file = new File(name);
        FileOutputStream fos = new FileOutputStream(file);
        byte[] buffer = new byte[1024 * 1024];  // 1 MB temp buffer
        int len;
        while ((len = ois.read(buffer)) != -1) {  // <--- StreamCorruptedException
            fos.write(buffer, 0, len);
        }
    }

reset(( 调用之所以存在,是因为没有它,缓存的数据量对于可怜的 Android 设备来说太多了,并且整个应用程序在 OOM 异常时崩溃。SO上有几篇帖子建议进行这样的修复。

问题是,如果我将 NetworkAttachment 的多个实例放入一个数组中并尝试通过网络对其进行序列化,它并非在所有情况下都有效。

如果两个Android设备相互流式传输序列化数据,没问题,我可以传输10的MB,一切都很好。

但是,当一台Android设备将文件上传到Java服务器应用程序(JDK 7(时,我得到:

java.io.StreamCorruptedException: 意外重置;递归深度:2 at java.io.ObjectInputStream.handleReset(ObjectInputStream.java:2028( at java.io.ObjectInputStream.access$600(ObjectInputStream.java:206( 在 java.io.ObjectInputStream$BlockDataInputStream.readBlockHeader(ObjectInputStream.java:2510( 在 java.io.ObjectInputStream$BlockDataInputStream.refill(ObjectInputStream.java:2550( 在 java.io.ObjectInputStream$BlockDataInputStream.read(ObjectInputStream.java:2709( at java.io.ObjectInputStream.read(ObjectInputStream.java:865( at java.io.InputStream.read(InputStream.java:101( at com.croconaut.network.NetworkAttachment.readObject(NetworkAttachment.java:186( at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method( at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57( 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43( at java.lang.reflect.Method.invoke(Method.java:606( at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1058( 在 java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1897( 在 java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798( at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350( at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370( at java.util.ArrayList.readObject(ArrayList.java:771( at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method( at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57( 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43( at java.lang.reflect.Method.invoke(Method.java:606( at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1058( 在 java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1897( 在 java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798( at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350( at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370( at com.croconaut.CptServer$2$1.run(CptServer.java:148(

如果我删除 reset(( 调用,它(自然(有效。但是,我迫切需要 reset(( 调用来降低内存消耗,那么我在这里有什么选择?

不应在 writeObject() 方法中调用 reset()。在调用代码中在外面调用它。无论如何,它不会有太大的影响,并且在写入循环中调用它是毫无意义的。

最后,我以不同的方式实现了它(不使用ObjectOutputStream(,但问题在于JDK不兼容 - Android端运行JDK 6(由Google(和服务器运行JDK 7(由Oracle(。也许流代码中有一些代码更改,并且没有保留 reset(( 兼容性。

相关内容

  • 没有找到相关文章

最新更新