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 个字节的去向。

谢谢!

--edit: 添加 if(oos!=null) { ... } 以防止 NPE

4

4 回答 4

3

ObjectOutputStream用于序列化对象。您不应该对数据的存储方式做出任何假设。

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

于 2012-02-27T13:59:51.070 回答
2

ObjectOutputStream 在开头写入一个标头。

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

于 2012-02-27T13:55:17.713 回答
0

ObjectOutputStream 的 JavaDoc 告诉您:

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

所以阻塞的东西可能是你缺少的开销。

于 2012-02-27T13:58:25.377 回答
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

于 2012-02-27T14:07:21.763 回答