最初,我们使用Java中的FileOutputStream来创建OutputStream,该Files.newOutputStream会将数据简单地传输到文件中。

从Java 7开始,我们还可以调用FileOutputStream,它为我们创建了行为完全相同的Stream(“构造函数”参数略有不同)。

至少在OpenJDK 8中,旧的Files.newOutputStream的write方法是作为 native 方法实现的,而由ByteChannel创建的OutputStream创建了ojit_code,然后由委托(delegate)给ByteChannel的OutputStream对其进行包装。

第二种方法使调用调用的所有包装程序都变得非常复杂。一些幼稚的性能测试表明,新方法要快一点,但这并不是很多,几乎不值得一提。但是也许我没有选择最佳用例。

OpenJDK中基于ByteChannel的新实现背后的原因是什么?是速度吗?在某些情况下,这实际上会更快吗?为什么?

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

最佳答案



这并非总是如此。这取决于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,并使用 .newByteChannel() 包装Channels.newChannel()调用。

因此,答案确实是:取决于情况。但是OpenJDK家伙不是初学者,如果他们做出了这样的选择,那么他们就有充分的理由。

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

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

10-07 22:45