为什么我只能使用ObjectInputStream一次读取1024个字节?

时间:2015-11-29 06:24:21

标签: java objectinputstream objectoutputstream

我编写了以下代码,将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字节发生的暂停有关?为什么这有必要?

3 个答案:

答案 0 :(得分:19)

对象流使用内部1024字节缓冲区,并以块大小标记为首的块中以该大小的块写入原始数据,这些块是猜测,0x7A后跟一个32位长字(或0x77后跟8位长字)。因此,您最多只能读取1024个字节。

这里真正的问题是你为什么只使用对象流来读写字节。使用缓冲流。然后缓冲在你的控制之下,顺便说一下,空间开销为零,与具有流标题和类型代码的对象流不同。

NB序列化数据不是文本,不应存储在名为.txt的文件中。

答案 1 :(得分:8)

ObjectOutputStreamObjectInputStream是用于序列化对象的特殊流。

但是当你执行stream.write(bytes);时,你试图使用ObjectOutputStream作为常规流,写入4000字节,而不是写入一个字节数组对象。当数据写入ObjectOutputStream时,它们将被专门处理。

来自documentation of ObjectOutputStream

(强调我的。)

  

原始数据(不包括可序列化字段和可外部化数据)将写入块数据记录中的ObjectOutputStream。块数据记录由标题和数据组成。块数据头由标记和标头后面的字节数组成。连续的原始数据写入被合并到一个块数据记录中。 用于块数据记录的阻塞因子将是1024字节。每个块数据记录最多可填充1024个字节,或者在块数据模式终止时写入。

我希望从中可以看出为什么你会收到这种行为。

我建议您使用BufferedOutputStream代替ObjectOutputStream,或者,如果您确实想使用ObjectOutputStream,请使用writeObject()代替write() }。相应的内容适用于输入。

答案 2 :(得分:4)

我建议您使用try-with-resources Statement来处理关闭资源,使用BufferedInputStreamBufferedOutputStream添加缓冲,然后使用writeObjectreadObject来序列化你的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();