DataOutputStream 和 ObjectOutputStream 有啥区别?

Posted

技术标签:

【中文标题】DataOutputStream 和 ObjectOutputStream 有啥区别?【英文标题】:What's the difference between DataOutputStream and ObjectOutputStream?DataOutputStream 和 ObjectOutputStream 有什么区别? 【发布时间】:2012-07-16 06:54:06 【问题描述】:

我正在学习 Java 中的套接字编程。我见过一些使用DataOutputStream 和一些使用ObjectOutputStream 的客户端/服务器应用程序示例。

这两者有什么区别?

有性能差异吗?

【问题讨论】:

阅读 ObjectOutputStream 以获取详细的示例说明。 【参考方案1】:

DataInput/OutputStream 通常表现更好,因为它更简单。它只能读/写原始类型和字符串。

ObjectInput/OutputStream 可以读/写任何对象类型以及原语。如果您想发送复杂的数据,它的效率较低,但更易于使用。

我会假设 Object*Stream 是最佳选择,直到您知道它的性能是一个问题。

【讨论】:

谢谢彼得,正是我希望得到的那种简洁的答案 :-) @Peter Lawrey 你提到 ObjectInput/OutputStream 可以发送复杂的数据。你说的复杂数据是什么意思?你能解释一下吗 InputStream 和 OutputStream 是您可以使用的最通用的 IO 流,它们是 Java 中所有流的基类。 @JaiminPatel 虽然你经常想写一个原语而不仅仅是字节。【参考方案2】:

这可能对几年后仍在寻找答案的人有用...根据我在最近的 JVM (1.8_51) 上的测试,ObjectOutput/InputStream 的读/写速度几乎比DataOutput/InputStream 快 2 倍一个巨大的 double 数组!

以下是写入 1000 万个项目数组的结果(对于 100 万个结果基本相同)。为了完整起见,我还包括了文本格式(BufferedWriter/Reader):

TestObjectStream written 10000000 items, took: 409ms, or 24449.8778 items/ms, filesize 80390629b
TestDataStream written 10000000 items, took: 727ms, or 13755.1582 items/ms, filesize 80000000b
TestBufferedWriter written 10000000 items, took: 13700ms, or 729.9270 items/ms, filesize 224486395b

阅读:

TestObjectStream read 10000000 items, took: 250ms, or 40000.0000 items/ms, filesize 80390629b
TestDataStream read 10000000 items, took: 424ms, or 23584.9057 items/ms, filesize 80000000b
TestBufferedWriter read 10000000 items, took: 6298ms, or 1587.8057 items/ms, filesize 224486395b

我相信 Oracle 在最近的 Java 版本中已经对使用 ObjectStreams 的 JVM 进行了大量优化,因为这是写入/读取数据(包括序列化)的最常见方式,因此位于 Java 性能关键路径上。

所以看起来今天没有太多理由再使用DataStreams。 “不要试图智取JVM”,用最直接的方式,就是ObjectStreams :)

这是测试的代码:

class Generator 
    private int seed = 1235436537;
    double generate(int i) 
        seed = (seed + 1235436537) % 936855463;
        return seed / (i + 1.) / 524323.;
    


class Data 
    public final double[] array;
    public Data(final double[] array) 
        this.array = array;
    


class TestObjectStream 
    public void write(File dest, Data data) 
        try (ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(dest)))) 
            for (int i = 0; i < data.array.length; i++) 
                out.writeDouble(data.array[i]);
            
         catch (IOException e) 
            throw new RuntimeIoException(e);
        
    
    public void read(File dest, Data data) 
        try (ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(new FileInputStream(dest)))) 
            for (int i = 0; i < data.array.length; i++) 
                data.array[i] = in.readDouble();
            
         catch (IOException e) 
            throw new RuntimeIoException(e);
        
    


class TestDataStream 
    public void write(File dest, Data data) 
        try (DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(dest)))) 
            for (int i = 0; i < data.array.length; i++) 
                out.writeDouble(data.array[i]);
            
         catch (IOException e) 
            throw new RuntimeIoException(e);
        
    
    public void read(File dest, Data data) 
        try (DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(dest)))) 
            for (int i = 0; i < data.array.length; i++) 
                data.array[i] = in.readDouble();
            
         catch (IOException e) 
            throw new RuntimeIoException(e);
        
    


class TestBufferedWriter 
    public void write(File dest, Data data) 
        try (BufferedWriter out = new BufferedWriter(new FileWriter(dest))) 
            for (int i = 0; i < data.array.length; i++) 
                out.write(Double.toString(data.array[i]));
                out.newLine();
            
         catch (IOException e) 
            throw new RuntimeIoException(e);
        
    
    public void read(File dest, Data data) 
        try (BufferedReader in = new BufferedReader(new FileReader(dest))) 
            String line = in.readLine();
            int i = 0;
            while (line != null) 
                if(!line.isEmpty()) 
                    data.array[i++] = Double.parseDouble(line);
                
                line = in.readLine();
            
         catch (IOException e) 
            throw new RuntimeIoException(e);
        
    


@Test
public void testWrite() throws Exception 
    int N = 10000000;
    double[] array = new double[N];
    Generator gen = new Generator();
    for (int i = 0; i < array.length; i++) 
        array[i] = gen.generate(i);
    
    Data data = new Data(array);

    Map<Class, BiConsumer<File, Data>> subjects = new LinkedHashMap<>();
    subjects.put(TestDataStream.class, new TestDataStream()::write);
    subjects.put(TestObjectStream.class, new TestObjectStream()::write);
    subjects.put(TestBufferedWriter.class, new TestBufferedWriter()::write);

    subjects.forEach((aClass, fileDataBiConsumer) -> 

        File f = new File("test." + aClass.getName());

        long start = System.nanoTime();
        fileDataBiConsumer.accept(f, data);
        long took = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);

        System.out.println(aClass.getSimpleName() + " written " + N + " items, took: " + took + "ms, or " + String.format("%.4f", (N / (double)took)) + " items/ms, filesize " + f.length() + "b");
    );



@Test
public void testRead() throws Exception 
    int N = 10000000;
    double[] array = new double[N];
    Data data = new Data(array);

    Map<Class, BiConsumer<File, Data>> subjects = new LinkedHashMap<>();
    subjects.put(TestDataStream.class, new TestDataStream()::read);
    subjects.put(TestObjectStream.class, new TestObjectStream()::read);
    subjects.put(TestBufferedWriter.class, new TestBufferedWriter()::read);

    subjects.forEach((aClass, fileDataBiConsumer) -> 
        File f = new File("test." + aClass.getName());

        long start = System.nanoTime();
        fileDataBiConsumer.accept(f, data);
        long took = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);

        System.out.println(aClass.getSimpleName() + " read " + N + " items, took: " + took + "ms, or " + String.format("%.4f", (N / (double)took)) + " items/ms, filesize " + f.length() + "b");
    );

【讨论】:

有趣!感谢您的信息。 可能在第一次运行 TestObjectStream 后运行 TestDataStream 会减慢它的速度。数据流和对象流使用相同的逻辑来读取/写入流。那为什么他们的运行时间会不同呢?【参考方案3】:

DataOutputStreamObjectOutputStream:在处理基本类型时,除了ObjectOutputStream 创建的标头之外没有区别。

使用ObjectOutputStream 类,实现Serializable 的类的实例可以写入输出流,并且可以使用ObjectInputStream 读回。

DataOutputStream 只能处理基本类型。

【讨论】:

【参考方案4】:

只有实现java.io.Serializable 接口的对象才能使用ObjectOutputStream 写入流。原始数据类型也可以使用DataOutput 中的适当方法写入流。也可以使用 writeUTF 方法写入字符串。但另一方面,DataInputStream 允许应用程序以可移植的方式将原始 Java 数据类型写入输出流。

Object OutputStream

Data Input Stream

【讨论】:

不正确。原语可以写入ObjectOutputStream Only objects that support the java.io.Serializable interface can be written to streams 请从我提供的上述 javadocs 链接中查看这一行。类描述说实现了Serializable接口就可以写,我没提过原始类型不能写到这个流中 @sasidhar 那么您应该考虑更改答案的措辞,因为这意味着只有Objects 可以写入ObjectOutputStream。 (这可能就是为什么你有 2 票反对)

以上是关于DataOutputStream 和 ObjectOutputStream 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

DataOutputStream和DataInputStream

Java IO DataInputStream 和 DataOutputStream

大数据必学Java基础(七十三):数据流DataInputStream和DataOutputStream介绍

JAVA IO操作:数据操作流:DataOutputStream和DataInputStream

数据流: DataInputStream 和 DataOutputStream

DataInputStream和DataOutputStream