Files.newOutputStream vs FileOutputStream

时间:2016-02-19 15:38:05

标签: java openjdk

最初我们在Java中使用FileOutputStream来创建OutputStream,只需将数据传输到文件中。

从Java 7开始,我们也可以调用Files.newOutputStream为我们创建一个行为完全相同的流(除了"构造函数" -arguments中的细微差别)。

至少在OpenJDK 8中,旧FileOutputStream的写入方法是作为本机方法实现的,而Files.newOutputStream创建的OutputStream则创建ByteChannel,然后由一个委托给ByteChannel的OutputStream包装。

第二种方法读取相当复杂,所有包装器都会调用write。一些天真的性能测试表明,新方法的速度要快一点,但这并不是很多,也很难提及。但是,也许我没有选择最好的用例。

OpenJDK中基于ByteChannel的新实现背后的原因是什么?速度快吗?是否存在实际上明显更快的情况?为什么?

(我知道这是依赖于JRE的,不应该依赖于确切的实现。这主要是对背景的好奇心。)

1 个答案:

答案 0 :(得分:2)

  

当Files.newOutputStream创建的OutputStream创建一个ByteChannel,然后由一个委托给ByteChannel的OutputStream包装。

这并非总是如此。这取决于FileSystem实施!或者,更准确地说,是FileSystemProvider实施。

默认实现确实如此(注意:不是OpenJDK,而是Oracle' 8u75,非常接近):

public OutputStream newOutputStream(Path path, OpenOption... options)
    throws IOException
{
    int len = options.length;
    Set<OpenOption> opts = new HashSet<OpenOption>(len + 3);
    if (len == 0) {
        opts.add(StandardOpenOption.CREATE);
        opts.add(StandardOpenOption.TRUNCATE_EXISTING);
    } else {
        for (OpenOption opt: options) {
            if (opt == StandardOpenOption.READ)
                throw new IllegalArgumentException("READ not allowed");
            opts.add(opt);
        }
    }
    opts.add(StandardOpenOption.WRITE);
    return Channels.newOutputStream(newByteChannel(path, opts));
}

但是它不一定是这样的

另一个FileSystemProvider实现可能会选择直接返回OutputStream并使用Channels.newChannel()来回复.newByteChannel()次调用。

所以,答案确实是:它取决于。但OpenJDK的人不是初学者,如果他们做出了这个选择,他们就有充分的理由。

是的,他们当然做了性能测试:p

例证:我在Dropbox上有一个JSR 203实现(虽然代码很老);在此实施中,FileSystemProvider.newOutputStream()调用this method。实际上甚至不支持.newByteChannel()(在与nio-dev的专家交谈之后,看起来这是一个错误;但是文档没有提到需要实现)