java ObjectOutputStream中的开销?

时间:2012-02-27 13:47:12

标签: java serialization bytearray objectoutputstream

我对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

4 个答案:

答案 0 :(得分:3)

ObjectOutputStream用于序列化对象。您不应该假设数据是如何存储的。

如果您只想存储原始数据,请使用DataOutputStream

答案 1 :(得分:1)

ObjectOutputStream在开头写入标题。

您可以通过继承ObjectOutputStream并实现writeStreamHeader()来消除此标头。

答案 2 :(得分:0)

ObjectDutputStream的JavaDoc告诉您:

  

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

所以阻塞的东西可能是你失去的开销。

答案 3 :(得分: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