Java ObjectOutputStream中的开销问题?

5
我对ObjectOutputStream的行为感到困惑。写入数据时似乎有9字节的开销。请考虑下面的代码:
float[] speeds = new float[96];
float[] flows = new float[96];

//.. do some stuff here to fill the arrays with data

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos=null;
try {
    oos = new ObjectOutputStream(baos);
    oos.writeInt(speeds.length);
    for(int i=0;i<speeds.length;i++) {
        oos.writeFloat(speeds[i]);
    }
    for(int i=0;i<flows.length;i++) {
        oos.writeFloat(flows[i]);
    }
    oos.flush();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    try {
        if(oos!=null) {
            oos.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

byte[] array = baos.toByteArray();

数组的长度始终为781,而我预期它应该是(1 + 96 + 96)* 4 = 772个字节。我似乎找不到这9个字节的去向。
谢谢!
--编辑:添加if(oos!= null){ ... }以防止NPE

2
像大多数文件格式一样,它有一个头和版本号。如果你只是写原始数据类型,ObjectOutputStream 不是一个好的解决方案。此外,在 Java SE 7 中可以使用 try (Type resource = acquire()) { use(); } 或者 acquire(); try { use(); } finally { release(); }。你可能会遇到潜在的 NPE 问题,以及糟糕的错误处理。 - Tom Hawtin - tackline
嗨Tom,你说的空指针问题是对的。我已经在代码中修复了它。 - hinsbergen
1
NPE只是笨拙资源处理的副作用。一旦你放弃清晰的代码,出错就变得非常普遍。即使对于“Java安全编码标准(CERT Oracle Secure Coding Standard for Java)”,我也必须反复指出代码中的缺陷。保持简单。另外,不要害怕查看十六进制编辑器/查看器中的原始序列化数据! - Tom Hawtin - tackline
4个回答

3

2

ObjectOutputStream在开头写入一个标头。

您可以通过子类化ObjectOutputStream并实现writeStreamHeader()方法来消除此标头。


0
JavaDoc for ObjectOutputStream 告诉您:

原始数据(不包括可序列化字段和可外部化数据)将被写入块数据记录。块数据记录由头和数据组成。块数据头包括标记和要在头后面跟随的字节数。连续的原始数据写入将合并为一个块数据记录。用于块数据记录的阻塞因子将是1024个字节。每个块数据记录将填充到1024个字节,或者在块数据模式终止时进行写入。对ObjectOutputStream方法writeObject、defaultWriteObject和writeFields的调用最初将终止任何现有的块数据记录。

因此,阻塞相关的内容可能是您缺失的开销。

0
Java的序列化流以4字节头(2字节“魔数”和2字节版本号)开头。接着是一系列块数据和对象条目。块数据条目有两种: “短” 和 “长”。 短块每个块有2字节的开销,块最多可以达到255个字节。长块的开销为5个字节,但它们可以长达4 GB。 "长" 块在实践中可以有多长取决于ObjectOutputStream内部缓冲区的大小。
在这种情况下,您只有一个长数据块条目,因此您看到的开销是来自流头的4个字节和来自数据块的5个字节,总共9个字节。
您可以在此处找到完整文档:http://docs.oracle.com/javase/7/docs/platform/serialization/spec/protocol.html

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接