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

Why can I only read 1024 bytes at a time with ObjectInputStream?

我编写了以下代码,将 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 个字节得到 "paused"(因为缺少更好的词)。

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个字节出现的停顿有关系吗?为什么这是必要的?

我建议您使用 try-with-resources Statement to handle closing your resources, add buffering with BufferedInputStream and BufferedOutputStream,然后使用 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();

object 流使用内部 1024 字节缓冲区,并以该大小的块写入原始数据,以块数据标记为首的流块写入,猜猜看,0x7A 后跟一个 32 位长度的字(或 0x77 后跟一个 8 位长度的字)。所以你最多只能读取 1024 个字节。

这里真正的问题是为什么您使用 object 流来读取和写入字节。使用缓冲流。然后缓冲在您的控制之下,顺便说一下,space 开销为零,这与具有流 headers 和类型代码的 object 流不同。

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

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

但是当您执行 stream.write(bytes); 时,您正在尝试将 ObjectOutputStream 用作常规流,用于写入 4000 字节,而不是用于写入字节数组对象。当数据像这样写入 ObjectOutputStream 时,它们会被特殊处理。

来自documentation of ObjectOutputStream

(强调我的。)

Primitive data, excluding serializable fields and externalizable data, is written to the ObjectOutputStream in block-data records. A block data record is composed of a header and data. The block data header consists of a marker and the number of bytes to follow the header. Consecutive primitive data writes are merged into one block-data record. The blocking factor used for a block-data record will be 1024 bytes. Each block-data record will be filled up to 1024 bytes, or be written whenever there is a termination of block-data mode.

我希望从这里可以清楚地看出您收到此行为的原因。

我建议您使用 BufferedOutputStream 而不是 ObjectOutputStream,或者,如果您真的想使用 ObjectOutputStream,则使用 writeObject() 而不是 write()。相应的适用于输入。