我编写了以下代码,将4000字节的0写入文件test.txt
。然后,我一次以1000字节的块读取相同的文件。
FileOutputStream output = new FileOutputStream("test.txt");
ObjectOutputStream stream = new ObjectOutputStream(output);
byte[] bytes = new byte[4000];
stream.write(bytes);
stream.close();
FileInputStream input = new FileInputStream("test.txt");
ObjectInputStream s = new ObjectInputStream(input);
byte[] buffer = new byte[1000];
int read = s.read(buffer);
while (read > 0) {
System.out.println("Read " + read);
read = s.read(buffer);
}
s.close();
我期望发生的是四次读取1000个字节。
Read 1000
Read 1000
Read 1000
Read 1000
然而,实际发生的事情是,我似乎每1024字节“暂停”(因为缺少一个更好的词)。
Read 1000
Read 24
Read 1000
Read 24
Read 1000
Read 24
Read 928
如果我尝试读取超过1024个字节,那么我的上限为1024字节。如果我尝试读取少于1024个字节,我仍然需要暂停1024字节标记。
在检查十六进制的输出文件test.txt
时,我注意到有一个5个非零字节序列7A 00 00 04 00
相隔1029个字节,尽管事实上我只写了0到文件。 Here is the output from my hex editor.(太长了,无法解决问题。)
所以我的问题是:当我写完全0时,为什么这五个字节出现在我的文件中?这5个字节是否与每1024字节发生的暂停有关?为什么这有必要?
答案 0 :(得分:19)
对象流使用内部1024字节缓冲区,并以块大小标记为首的块中以该大小的块写入原始数据,这些块是猜测,0x7A
后跟一个32位长字(或0x77
后跟8位长字)。因此,您最多只能读取1024个字节。
这里真正的问题是你为什么只使用对象流来读写字节。使用缓冲流。然后缓冲在你的控制之下,顺便说一下,空间开销为零,与具有流标题和类型代码的对象流不同。
NB序列化数据不是文本,不应存储在名为.txt的文件中。
答案 1 :(得分:8)
ObjectOutputStream
和ObjectInputStream
是用于序列化对象的特殊流。
但是当你执行stream.write(bytes);
时,你试图使用ObjectOutputStream
作为常规流,写入4000字节,而不是写入一个字节数组对象。当数据写入ObjectOutputStream
时,它们将被专门处理。
来自documentation of ObjectOutputStream
:
(强调我的。)
原始数据(不包括可序列化字段和可外部化数据)将写入块数据记录中的ObjectOutputStream。块数据记录由标题和数据组成。块数据头由标记和标头后面的字节数组成。连续的原始数据写入被合并到一个块数据记录中。 用于块数据记录的阻塞因子将是1024字节。每个块数据记录最多可填充1024个字节,或者在块数据模式终止时写入。
我希望从中可以看出为什么你会收到这种行为。
我建议您使用BufferedOutputStream
代替ObjectOutputStream
,或者,如果您确实想使用ObjectOutputStream
,请使用writeObject()
代替write()
}。相应的内容适用于输入。
答案 2 :(得分:4)
我建议您使用try-with-resources
Statement来处理关闭资源,使用BufferedInputStream
和BufferedOutputStream
添加缓冲,然后使用writeObject
和readObject
来序列化你的byte[]
。像,
try (OutputStream output = new BufferedOutputStream(//
new FileOutputStream("test.txt"), 8192); //
ObjectOutputStream stream = new ObjectOutputStream(output)) {
byte[] bytes = new byte[4000];
stream.writeObject(bytes);
} catch (IOException ioe) {
ioe.printStackTrace();
}
然后阅读
try (InputStream input = new BufferedInputStream(//
new FileInputStream("test.txt"), 8192); //
ObjectInputStream s = new ObjectInputStream(input)) {
byte[] bytes = (byte[]) s.readObject();
} catch (IOException | ClassNotFoundException ioe) {
ioe.printStackTrace();
}
如果涉及部分数组,则需要添加长度。您可以在另一边使用stream.writeInt(len);
和int len = stream.readInt();
。