java DataOutputStream 和 ObjectOutputStream 有什么区别?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11521027/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 05:24:57  来源:igfitidea点击:

What's the difference between DataOutputStream and ObjectOutputStream?

javaandroidsockets

提问by magritte

I'm learning about socket programming in Java. I've seen client/server app examples with some using DataOutputStream, and some using ObjectOutputStream.

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

What's the difference between the two?

两者有什么区别?

Is there a performance difference?

有性能差异吗?

回答by Peter Lawrey

DataInput/OutputStream performs generally better because its much simpler. It can only read/write primtive types and Strings.

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

ObjectInput/OutputStream can read/write any object type was well as primitives. It is less efficient but much easier to use if you want to send complex data.

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

I would assume that the Object*Stream is the best choice until you knowthat its performance is an issue.

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

回答by Denis

This might be useful for people still looking for answers several years later... According to my tests on a recent JVM (1.8_51), the ObjectOutput/InputStreamis surprisingly almost 2x times faster than DataOutput/InputStreamfor reading/writing a huge array of double!

这对于几年后仍在寻找答案的人可能很有用......根据我对最近的 JVM (1.8_51) 的测试,ObjectOutput/InputStream令人惊讶的是,它比DataOutput/InputStream读取/写入大量双精度数组快近 2 倍!

Below are the results for writing 10 million items array (for 1 million the results are the essentially the same). I also included the text format (BufferedWriter/Reader) for the sake of completeness:

下面是写入 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

Reading:

阅读:

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

I believe Oracle has heavily optimized the JVM for using ObjectStreams in last Java releases, as this is the most common way of writing/reading data (including serialization), and thus is located on the Java performance critical path.

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

So looks like today there's no much reason anymore to use DataStreams. "Don't try to outsmart JVM", just use the most straightforward way, which is ObjectStreams :)

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

Here's the code for the test:

这是测试的代码:

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");
    });
}

回答by Nikhil

DataOutputStreamand ObjectOutputStream: when handling basic types, there is no difference apart from the header that ObjectOutputStreamcreates.

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

With the ObjectOutputStreamclass, instances of a class that implements Serializablecan be written to the output stream, and can be read back with ObjectInputStream.

使用ObjectOutputStream该类,Serializable可以将实现的类的实例写入输出流,并且可以使用ObjectInputStream.

DataOutputStreamcan only handle basic types.

DataOutputStream只能处理基本类型。

回答by sasidhar

Only objects that implement the java.io.Serializableinterface can be written to streams using ObjectOutputStream.Primitive data types can also be written to the stream using the appropriate methods from DataOutput. Strings can also be written using the writeUTF method. But DataInputStreamon the other hand lets an application write primitive Java data typesto an output stream in a portable way.

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

Object OutputStream

对象输出流

Data Input Stream

数据输入流