- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我编写了一个自定义序列化/反序列化逻辑来保存一些数据,因为 Java 默认序列化结果是时间和内存都非常昂贵。为此,我为需要持久化的类编写了 readObject(ObjectInput in)
和 writeObject(ObjectOutput out)
方法。但是我注意到,如果我不在 writeObject(ObjectOutput out)
方法中使用任何 out.writeObject(obj)
,那么它总是会抛出 EOFException
。
考虑以下示例:
数据.java
public class Data implements BaseData {
private String messageUID;
private String rawData;
private String data;
private Long type;
private Boolean processed = false;
private String processedMessage;
private String processedDetaildMessage;
// getter setter
public void readObject(ObjectInput in) throws IOException, ClassNotFoundException {
messageUID = in.readUTF();
rawData = in.readUTF();
data = in.readUTF();
type = in.readLong();
processed = in.readBoolean();
if (processed) {
processedMessage = in.readUTF();
processedDetaildMessage = in.readUTF();
}
}
public void writeObject(ObjectOutput out) throws IOException {
out.writeUTF(messageUID);
out.writeUTF(rawData);
out.writeUTF(data);
out.writeLong(type);
out.writeBoolean(processed);
if (processed) {
out.writeUTF(processedMessage);
String tempDetailsMessage[] = processedDetaildMessage.split(" more");
out.writeUTF(tempDetailsMessage[tempDetailsMessage.length - 1]);
}
}
然而,每当我使用上面的代码时,out
流总是在末尾缺少一些信息(来自 processedDetaildMessage
字段)并且我得到 EOFException
从 in
中读取它时,下面的堆栈跟踪(Data.java 第 216 行是 processedDetaildMessage = in.readUTF()
);
java.io.EOFException
at java.io.ObjectInputStream$BlockDataInputStream.readByte(ObjectInputStream.java:2766)
at java.io.ObjectInputStream$BlockDataInputStream.readUTFChar(ObjectInputStream.java:3158)
at java.io.ObjectInputStream$BlockDataInputStream.readUTFBody(ObjectInputStream.java:3055)
at java.io.ObjectInputStream$BlockDataInputStream.readUTF(ObjectInputStream.java:2864)
at java.io.ObjectInputStream.readUTF(ObjectInputStream.java:1072)
at com.smartstream.common.Data.readObject(Data.java:216)
at com.smartstream.common.PerformanceTest.getObjectFromBytes(PerformanceTest.java:168)
at com.smartstream.common.PerformanceTest.access$0(PerformanceTest.java:160)
at com.smartstream.common.PerformanceTest$1.mapRow(PerformanceTest.java:119)
at com.smartstream.common.PerformanceTest$1.mapRow(PerformanceTest.java:1)
at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:92)
at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:60)
at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:651)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:589)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:639)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:668)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:676)
at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:731)
at com.smartstream.common.PerformanceTest.readFromDb(PerformanceTest.java:109)
at com.smartstream.common.PerformanceTest.main(PerformanceTest.java:66)
所以我虽然在写完所有必填字段后会在末尾放置一些额外的字节信息,但不会读取它们,这样我在读取时就不会到达文件末尾。我尝试了所有这些 out.writeByte(-1)
、out.writeInt(-1)
、out.writeLong(2342343l)
、out.writeUTF("END_OF_STREAM")
但这些没有区别。最后我做了这个 out.writeObject(new String("END_OF_STREAM"))
并且它工作正常。如果没有使用 writeObject()
方法写入信息,有人可以解释为什么输出流会遗漏一些信息。下面是我如何读写流;
private byte[] getObjectAsBytes(Data data) {
byte[] byteArray = null;
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
try {
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
// Use this for java default serialization
// oos.writeObject(data);
data.writeObject(oos);
byteArray = bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (oos != null) {
try {
oos.flush();
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return byteArray;
}
private Data getObjectFromBytes(byte[] byteArray) {
Data data = new Data();
ByteArrayInputStream bais = null;
ObjectInputStream ois = null;
try {
bais = new ByteArrayInputStream(byteArray);
ois = new ObjectInputStream(bais);
// Use this for java default serialization
// data = (Data) ois.readObject();
data.readObject(ois);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return data;
}
如果有人感兴趣,下面是流中写的内容;
使用原始代码保留数据(抛出 EOFException
和丢失的信息)(不要将堆栈跟踪与原始问题混淆此堆栈跟踪作为字段 processedDetailedMessage
)
¬í---z-------3507319347632941385----FEEDER-----1437052314954 ---This is a random string---N---þ%J---!this is message of processed dataÛ
Caused by: java.sql.SQLException: ORA-01691: unable to extend lob segment TLM_DBO.SYS_LOB0000076335C00008$$ by 8192 in tablespace WIN_SL_TABLE
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:439)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:395)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:802)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:436)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:186)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:521)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:205)
at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:1008)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1307)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3449)
at oracle.jdbc.driver.OraclePre
使用 writeObject
方法在末尾写入额外字符串后保留数据
¬í---z-------3507319347632941385----FEEDER-----1437052314954 ---This is a random string---N---þ%J---!this is message of processed dataÛ
Caused by: java.sql.SQLException: ORA-01691: unable to extend lob segment TLM_DBO.SYS_LOB0000076335C00008$$ by 8192 in tablespace WIN_SL_TABLE
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:439)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:395)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:802)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:436)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:186)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:521)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:205)
at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:1008)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1307)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3449)
at oracle.jdbc.driver.OraclePrz-----NeparedStatement.execute(OraclePreparedStatement.java:3550)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.execute(OraclePreparedStatementWrapper.java:1374)
at com.ibm.ws.rsadapter.jdbc.WSJdbcPreparedStatement.pmiExecute(WSJdbcPreparedStatement.java:975)
at com.ibm.ws.rsadapter.jdbc.WSJdbcPreparedStatement.execute(WSJdbcPreparedStatement.java:642)
at com.smartstream.control.engine.config.dao.jdbc.ProcessExecutionAuditDetailDao$1.doInPreparedStatement(ProcessExecutionAuditDetailDao.java:115)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:586)
... 23t
END_OF_STREAM
PS ----代表不可读字节
最佳答案
您的持久化数据不完整,因为您在刷新 ObjectOutputStream 之前创建字节数组。在 getObjectAsBytes(Data)
中,在 finally block 之后移动 byteArray = bos.toByteArray();
以使其工作。或者,该方法可以更简洁地编写如下(需要 Java 7+):
private byte[] getObjectAsBytes(Data data) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {
data.writeObject(oos);
} catch (IOException e) {
e.printStackTrace();
}
return bos.toByteArray();
}
我在自己的程序中测试了这两种方式,它们都可以防止抛出 EOFException。
至于为什么有一个 writeObject 是有效的,那是因为 underlying writeObject implementation在方法的开头和结尾切换 block 数据模式,changing the block data mode performs a drain它将所有数据写入底层 OutputStream,对于 ByteArrayOutputStream,这实际上与刷新相同。
关于java - 为什么 ObjectOutputStream 和 ObjectInputStream 抛出 EOFException 的这种奇怪行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31455538/
当我尝试模拟 ObjectInputStream 对象时,我得到一个 NullPointerException。更准确地说,当调用此行时: when(inputStream.readObject())
这是我的代码: ObjectInputStream ois = null; UserRegistration UR = new UserRegistration(); Scan
所以我试图将一个对象从客户端发送到服务器,然后我用这个对象做一些事情。我验证了发送时对象包含数据。当我在调试器中读取对象时,它的所有属性均为 null。 下面是我发送对象的位置: private cl
我正在使用套接字对java网络进行编程,并使用简单对象在远程程序之间交换数据。 在本例中,我有一个使用以下方法构造的ObjectInputStream: new ObjectInputStream(S
我一直在尝试制作一款两人多米诺骨牌游戏。目前,我希望在玩家 2 的屏幕上模仿玩家 1 的 Action ,仅此而已。如果我启动玩家 1 的屏幕并移动一些多米诺骨牌,则当我启动玩家 2 的屏幕时会出现更
这个问题已经有答案了: Sending the same but modifed object over ObjectOutputStream (2 个回答) 已关闭 4 年前。 我正在尝试通过套接字
我在一个文件中存储了多个对象。这与 ObjectInputStream 有关。如果我有以下代码: FileInputStream fis = new FileInputStream(filename)
这个问题已经有答案了: Java socket/serialization, object won't update (2 个回答) 已关闭 8 年前。 我有多个客户端和一台服务器。服务器在一个线程中
我有一系列通过网络套接字发送的对象。 用于读取数据的代码已经实现并且可以工作,但我的问题是有时套接字超时会中断对象的读取(ObjectInputStream.readObject()),从而损坏流.
当我尝试从服务器发送一个对象时,我的计算机似乎崩溃了,第 27 行尝试接收该对象,我想我得到了一个无效的类型代码:0一次,但通常只是崩溃,所以我必须重新启动 new Thread(
我试图在第24行的客户端中实例化一个ObjectInputStream,但它不会,我可以实例化一个ObjectOutputStream,但不能实例化Input。 private class C
我正在尝试使用以下代码读取我保存的文件: public void saveOnFile() { try { ObjectOutputStream output = ne
我保存了一个ArrayList作为带有 ObjectOutputStream 的对象。现在,我如何在另一个应用程序项目上使用 ObjectInputStream 读取该对象?我尝试了一下,它抛出了 C
我有两个类。在第一个类中,我从List中写入数据,在第二堂课中,我想读取这些数据并将其放入listview中。它正确保存数据,但是当我尝试获取它时,logcat 给出错误: java.lang.Cla
我正在尝试将 ArrayList 发送到 Android 设备上的客户端。服务器说它发送了该对象,但是在 Android 设备上它挂起。我已经阅读过,在创建 ObjectInputStream 时,必
我正在通过 java 套接字将文件从 Google glass 设备读取到 PC。由于 catch 语句抛出 eof 异常,我的其余代码被忽略。我该如何解决这个问题? 代码:接收图像(并将其放入简单的
几天前,我开始编写一个小型多人游戏,其中我使用 ObjectInputStreams 和 ObjectOutputStreams 与服务器交换数据。但由于某种原因,服务器没有收到任何东西。所以我寻求一
我有一个套接字,它每隔几秒通过 ObjectOutputStream 向客户端发送一个对象列表。在服务器端,每次 writeObject(myList) 之后,我执行 flush 然后 reset。使
这个问题已经有答案了: ObjectInput and Output streams are not being accepted by client/server (2 个回答) 已关闭 5 年前。
我在使用二进制文件加载应用程序时遇到问题。我正在尝试从二进制文件中读取数据并将数据注入(inject)到我的应用程序中的一些 HashMaps/ArrayLists 中。 public void lo
我是一名优秀的程序员,十分优秀!