最初,我们使用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的专家交谈之后,看来这是一个错误;但是文档中没有提到需要实现)