我有一个包含对文件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) 在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) 在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) 在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) 在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) 在com.croconaut.CptServer $ 2 $ 1.run(CptServer.java:148)
如果我删除了reset()调用,它会自然地工作。但是,我迫切需要reset()调用以降低内存消耗,那么我的选择是什么?
答案 0 :(得分:0)
您不应在reset()
方法中调用writeObject()
。在调用代码中将其调用到外部。无论如何它都不会产生太大影响,在写循环中调用它是没有意义的。
答案 1 :(得分:-1)
最后,我以不同的方式实现了它(不使用ObjectOutputStream),但问题在于JDK不兼容 - 运行JDK 6(由Google运行)的Android端和运行JDK 7(由Oracle运行)的服务器。也许流代码中存在一些代码更改,并且没有保留reset()兼容性。