我有一个包含对文件 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(( 兼容性。