JAVA中flush()与reset()之间的区别

时间:2018-06-30 13:00:48

标签: java io reset flush

我只是想知道刷新和重置之间的区别是什么? 为什么在example中刷新后使用reset?如果通过刷新方法擦除了内存缓存,为什么要使用复位方法?

ObjectOutputStream oos = new ObjectOutputStream(bos);

while(true){
    oos.writeObject(object);
    oos.flush();
    oos.reset();

    object.x++;
}

3 个答案:

答案 0 :(得分:2)

  

reset()将忽略任何已写入到对象的对象的状态。   流。将状态重置为与新的ObjectOutputStream相同。   流中的当前点被标记为重置,因此   相应的ObjectInputStream将在同一点重置。   先前写入流中的对象将不会被称为   已经在流中。它们将再次写入流中。

     

flush()方法刷新流。这将写入任何缓冲   输出字节并刷新到基础流。

flush()方法将清除缓冲区并写入流,而reset()将用于更改已写入流的对象。

答案 1 :(得分:2)

  

如果通过刷新方法擦除了内存缓存,为什么要使用复位方法?

flush()将在基础ObjectOutputStream中写入OutputStream对象的缓冲区,但不会重置ObjectOutputStream对象的整个状态。

如果打开ObjectOutputStream源代码类,则可以看到缓冲区之外它包含许多实例字段。
这是一个小片段:

/** filter stream for handling block data conversion */
private final BlockDataOutputStream bout;
/** obj -> wire handle map */
private final HandleTable handles;
/** obj -> replacement obj map */
private final ReplaceTable subs;
/** recursion depth */
private int depth;
/** buffer for writing primitive field values */
private byte[] primVals;

有些人处理转换,其他人处理缓存,等等…… ObjectOutputStream.reset()将对此状态产生影响:

  

重置将忽略任何已写入到对象的对象的状态   流。

  

先前写入流中的对象将不称为   已经在流中。它们将再次写入流中。

ObjectOutputStream这些详细信息使用引用共享机制。
因此,在流中多次写入相同对象但状态不同的对象将多次写入原始状态的对象。
The top level documentation of ObjectOutputStream解释了更多内容(强调是我的):

  

对象的默认序列化机制写入   对象,类签名以及所有非瞬态值   和非静态字段。对其他对象的引用(   瞬态或静态字段)也会导致这些对象也被写入。   使用引用对单个对象的多个引用进行编码   共享机制,以便可以将对象图恢复到   

您现在应该了解reset()的含义。


示例说明ObjectOutputStream的缓存问题:

执行此类,编写10次相同对象,但状态不同的情况ObjectOutputStream,而在两次写作之间不调用reset()

public class FlushAndReset {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);

        Foo foo = new Foo();
        for (int i = 0; i < 10; i++) {
            foo.setValue(i);
            oos.writeObject(foo);
            oos.flush();
            // oos.reset();
        }

        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
        for (int i = 0; i < 10; i++) {
            Object obj = ois.readObject();
            System.out.println(obj);
        }
    }
}

Foo定义为:

public class Foo implements Serializable {

    private int value;

    public void setValue(int value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return "Foo [value=" + value + "]";
    }

}

当您阅读BOS的内容时,您将获得:

  

Foo [value = 0]

     

Foo [value = 0]

     

Foo [value = 0]

     

Foo [value = 0]

     

Foo [value = 0]

     

Foo [value = 0]

     

Foo [value = 0]

     

Foo [value = 0]

     

Foo [value = 0]

     

Foo [value = 0]

取消注释reset()的注释,您应该会看到更改:

  

Foo [value = 0]

     

Foo [value = 1]

     

Foo [value = 2]

     

Foo [value = 3]

     

Foo [value = 4]

     

Foo [value = 5]

     

Foo [value = 6]

     

Foo [value = 7]

     

Foo [value = 8]

     

Foo [value = 9]

答案 2 :(得分:0)

reset()将使所有已发送的对象无效。如果再次发送未更改的对象,则仅传输参考,从而允许重用已传输对象的缓存版本。这比始终发送整个对象要高效得多。

在您的示例中,对象的成员x的值增加了,因此对象发生了变化。如果您需要发送更改的值,则必须先调用reset(),以便将该对象实际重写到流中。

另一方面,flush()仅确保将数据实际写入流中。写入操作只会将数据放入缓冲区,并可能根据缓冲区大小将其写入流。调用flush()将保证数据已写入流中。但是flush将清除缓存的对象。