前言
在上传文件的时候,发现还有一个新的东西叫做Files.newInputStream
,就稍微看了一下下。主要应用示例在这篇文章中,也可以看这里。
FileInputStream
很久很久以前大家就在用这个库了,是一个文件流,可以读取文件。
主要用法也是直接新建:
FileInputStream fis = new FileInputStream("filePath");
或者
FileInputStream fis = new FileInputStream(new File("filePath"));
在源码中这两个的效果也是一样的。
使用完毕后,关闭:
fis.close();
或者你想稳妥一点:
fis.finalize();
这个库主要就是以只读的方式打开文件,读取文件,最后处理。就不再多说了。网上研究这个的人比我吃的饭都多。
Files.newInputStream
这个库是java.nio.file.Files
中的方法,是FileInputStream
的升级版。
我们来看看这个玩意的源码是什么意思:
public static InputStream newInputStream(Path path, OpenOption... options) throws IOException {
return provider(path).newInputStream(path, options);
}
通过自己的静态方法provider
,获取到FileSystemProvider
,然后调用newInputStream
方法。
这个FileSystemProvider
是一个抽象类,也提供了一个newInputStream
方法:
public InputStream newInputStream(Path path, OpenOption... options) throws IOException {
if (options.length > 0) {
for (OpenOption opt: options) {
// All OpenOption values except for APPEND and WRITE are allowed
if (opt == StandardOpenOption.APPEND ||
opt == StandardOpenOption.WRITE)
throw new UnsupportedOperationException("'" + opt + "' not allowed");
}
}
return Channels.newInputStream(Files.newByteChannel(path, options));
}
在这里,将通过Channels
类的newInputStream
方法给出输入流。
为什么偏偏要这么做呢?
最后看到这个方法是这样的:
/**
* Constructs a stream that reads bytes from the given channel.
*
* <p> The <tt>read</tt> methods of the resulting stream will throw an
* {@link IllegalBlockingModeException} if invoked while the underlying
* channel is in non-blocking mode. The stream will not be buffered, and
* it will not support the {@link InputStream#mark mark} or {@link
* InputStream#reset reset} methods. The stream will be safe for access by
* multiple concurrent threads. Closing the stream will in turn cause the
* channel to be closed. </p>
*
* @param ch
* The channel from which bytes will be read
*
* @return A new input stream
*/
public static InputStream newInputStream(ReadableByteChannel ch) {
checkNotNull(ch, "ch");
return new sun.nio.ch.ChannelInputStream(ch);
}
不难看出,这个方法的优势正如注释所述,是线程安全的。
为什么偏偏他是线程安全的?
这就是sun.nio.ch
的ChannelInputStream
类的作用了。这个类以ReadableByteChannel
作为构造函数。ReadableByteChannel
类是这样注释的:
/**
* A channel that can read bytes.
*
* <p> Only one read operation upon a readable channel may be in progress at
* any given time. If one thread initiates a read operation upon a channel
* then any other thread that attempts to initiate another read operation will
* block until the first operation is complete. Whether or not other kinds of
* I/O operations may proceed concurrently with a read operation depends upon
* the type of the channel. </p>
*
*
* @author Mark Reinhold
* @author JSR-51 Expert Group
* @since 1.4
*/
public interface ReadableByteChannel extends Channel {}
这就是线程安全的非阻塞IO
的核心了。
所以,不难看出,这个类最核心的地方就是将IO
模式转变为非阻塞的NIO
模式,这也顺应了现阶段高吞吐量或处理大文件的应用场景,趁着CPU
把任务丢给磁盘的时候,趁着闲下来的时间做点别的事,提升处理效率。
而这一点,也使得Files.newInputStream
能够进一步与其他的NIO
操作集成,从而在处理大文件的时候,充分利用缓冲区的优势,处理起来也比FileInputStream
要快很多。