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

我编写了以下代码,该代码将4000字节的0s写入文件。然后,我一次以1000字节的块读取同一文件。test.txt

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 个字节标记处暂停。

在检查十六进制的输出文件时,我注意到有一个相距5个非零字节1029字节的序列,尽管我只向文件写入了0s。这是我的十六进制编辑器的输出。(太长了,不适合问题。test.txt7A 00 00 04 00

所以我的问题是:为什么当我完全写0s时,这五个字节会出现在我的文件中?这 5 个字节是否与每 1024 个字节发生的暂停有关?为什么这是必要的?


答案 1

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

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

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


答案 2

ObjectOutputStream并且是用于对象序列化的特殊流。ObjectInputStream

但是当你这样做时,你试图将 用作常规流,用于写入4000字节,而不是用于写入字节数组对象。当数据像这样写入时,它们被特殊处理。stream.write(bytes);ObjectOutputStreamObjectOutputStream

ObjectOutputStream 的文档:

(强调我的。

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

我希望从这一点可以明显看出为什么你会受到这种行为。

我建议您要么使用而不是 ,要么,或者,如果您真的想使用 ,则使用而不是 。相应的内容适用于输入。BufferedOutputStreamObjectOutputStreamObjectOutputStreamwriteObject()write()


推荐