繁体   English   中英

DataOutputStream和ObjectOutputStream之间有什么区别?

[英]What's the difference between DataOutputStream and ObjectOutputStream?

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

这两者有什么区别?

有性能差异吗?

DataInput / OutputStream通常执行得更好,因为它更简单。 它只能读/写初始类型和字符串。

ObjectInput / OutputStream可以读/写任何对象类型以及原语。 如果要发送复杂数据,效率会降低,但更容易使用。

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

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

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

DataOutputStream只能处理基本类型。

这可能对几年后仍在寻找答案的人有用...根据我在最近的JVM(1.8_51)上的测试, ObjectOutput/InputStreamDataOutput/InputStream快几乎是读取/写入大数组的2倍快双倍!

下面是写入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版本中对使用ObjectStream的JVM进行了大量优化,因为这是编写/读取数据(包括序列化)的最常用方式,因此位于Java性能关键路径上。

所以看起来今天没有太多理由再使用DataStream “不要试图超越JVM”,只需使用最直接的方式,即ObjectStream s :)

这是测试的代码:

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

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

对象OutputStream

数据输入流

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM