最初我们在Java中使用FileOutputStream
来创建OutputStream
,只需将数据传输到文件中。
从Java 7开始,我们也可以调用Files.newOutputStream
为我们创建一个行为完全相同的流(除了"构造函数" -arguments中的细微差别)。
至少在OpenJDK 8中,旧FileOutputStream
的写入方法是作为本机方法实现的,而Files.newOutputStream
创建的OutputStream则创建ByteChannel
,然后由一个委托给ByteChannel的OutputStream包装。
第二种方法读取相当复杂,所有包装器都会调用write。一些天真的性能测试表明,新方法的速度要快一点,但这并不是很多,也很难提及。但是,也许我没有选择最好的用例。
OpenJDK中基于ByteChannel的新实现背后的原因是什么?速度快吗?是否存在实际上明显更快的情况?为什么?
(我知道这是依赖于JRE的,不应该依赖于确切的实现。这主要是对背景的好奇心。)
答案 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的专家交谈之后,看起来这是一个错误;但是文档没有提到需要实现)