您好我是Java和学习的新手,我在这里搜索了这个问题的答案并用Google搜索,查看了Java Doc但似乎无法找到关于这个主题的明确解释。
当包装流和Serializable对象时,将对象,数据,基元的混合写入文件,然后再读回它们,数据,对象,基元必须以与写入时相同的顺序读回。如果类型或错误序列不匹配,则会出现EOFException。
在回读文件时,Java如何知道对象和数据的类型?我只能断定这是存储在文件中,还是FileDescriptor?但是在Java文档中没有任何相关内容?或者在那里?
编辑:我已经测试了这个(Java 8),如果我的序列错误,我会得到一个EOFException,并且只是在读取文件时才得到Exception。EDIT2:对不起我没有发布代码,有点丢失它,因为我做了很多不同的流写入和读取,并在开始读取文件时纠正了类型错误带走了异常,多次得到EOFException。代码如下,必须从内存中重新创建。
try (DataOutputStream dataOut = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(dataFile)))) {
for (int i = 0; i < prices.length; i++) {
dataOut.writeDouble(prices[i]);
dataOut.write(numbers[i]);
dataOut.writeUTF(desc[i]);
}
try (DataInputStream dataIn = new DataInputStream(new BufferedInputStream(
new FileInputStream(dataFile)));) {
double price;
int number;
String description;
int c = 0;
while (true) {
price = dataIn.readDouble();
number = dataIn.readInt();
description = dataIn.readUTF();
System.out.println(price + " " + number + " " + description);
我省略了一些代码,但核心元素在那里,所以readInt方法产生一个EOFException,(使用的是write方法,而不是writeInt)。如果我更正错误(更改为writeInt)一切正常。但是,如果我在阅读时在价格和数字之间交换位置没有错误并打印出垃圾,但仍然正常完成。
while (true) {
description = dataIn.readUTF();
price = dataIn.readDouble();
number = dataIn.readInt();
但是如果我在读取文件时移动readUTF,我又会再次获得EOFException。
答案 0 :(得分:51)
如果类型或错误序列不匹配,则会出现EOFException。
不,这根本不是真的 - 至少在一般情况下不是这样。如果您过早地到达数据末尾,您将获得EOFException
。如果您只是使用错误的方法读取数据,但仍然读取相同数量的数据(例如,两次调用readInt
而不是readLong
一次),您将获得无用的数据,但也不例外。 (对此有豁免 - 如果您使用readUTF
,如果数据无效,则会出现例外修改UTF-8。或者readUTF
可以抛出如果长度前缀表示字符串比流中的数据长,那么EOFException
- 再次,这是读取流的末尾的问题。)
这是一个完整的例子:
import java.io.*;
public class Test {
public static void main(String[] args) throws IOException {
byte[] data;
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
try (DataOutputStream dos = new DataOutputStream(baos)) {
dos.writeLong(123456789012345L);
}
data = baos.toByteArray();
}
try (ByteArrayInputStream bais = new ByteArrayInputStream(data)) {
try (DataInputStream dis = new DataInputStream(bais)) {
System.out.println(dis.readInt()); // 28744
System.out.println(dis.readInt()); // -2045911175
}
}
}
}
请注意,在使用ObjectOutputStream
时,当您致电writeObject
时 将类型名称作为数据的一部分写入,以便在您致电readObject
时它知道要创建什么样的对象。但是,原始读/写方法(例如上面使用的方法)仍然没有留下任何数据类型的指示。在上面的代码中将DataObjectStream
/ DataInputStream
更改为ObjectOutputStream
/ ObjectInputStream
不会改变结果。
如果你调用readObject
,并且流被放置在对象数据的开头,它仍然不会抛出EOFException
- 它只会读取正确类型的对象,如果你施放错误的类型你会得到一个ClassCastException
。 (没有办法说“我希望现在就读Foo
。”)如果你打电话给readObject
并且 然后根据 存在的数据,可能发生任何奇怪的事情。
如果您尝试阅读数据末尾,则只会获得EOFException
,但是您这样做了 - 例如撰写long
,然后阅读三个 int
值。
作为readUTF
如何导致EOFException
的示例,请考虑以下代码:
import java.io.*;
public class Test {
public static void main(String[] args) throws IOException {
byte[] data;
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
try (DataOutputStream dos = new DataOutputStream(baos)) {
dos.writeShort(10000);
for (int i = 0; i < 500; i++) {
dos.write(0);
}
}
data = baos.toByteArray();
}
try (ByteArrayInputStream bais = new ByteArrayInputStream(data)) {
try (DataInputStream dis = new DataInputStream(bais)) {
System.out.println(dis.readUTF());
}
}
}
}
我们开始编写short
值10000,然后我们写500个其他字节。当我们调用readUTF
时,它将读取10000的值,然后期望能够读取10000多个字节,因为这是格式readUTF
期望的(长度,数据)。由于没有足够的数据, 将失败并显示EOFException
。如果您将writeShort(10000)
更改为writeShort(100)
,那么异常就会消失 - 即使您仍然没有将写入与读取匹配。