Java NIO 2.0相关知识点( 二 )

第二个参数 FileVisitor 被称为文件访问器接口 , 它实现起来非常复杂 , 要实现 5 个方法呢 , 但幸好 JDK 的设计者提供了一个默认的实现类 SimpleFileVisitor , 如果我们只想从目录树中找到 txt 后缀的文件 , 可以这样做:
// 相对路径Path dir = Paths.get("chenmo");try { Files.walkFileTree(dir, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { if (file.toString().endsWith(".txt")) { System.out.println(file.getFileName()); } return FileVisitResult.CONTINUE; } });} catch (IOException e) { e.printStackTrace();}通过创建匿名内部类来重写 SimpleFileVisitor 的 visitFile 方法 , 如果后缀名为 txt 就打印出来 。
04、文件的删除、复制、移动
创建一个文件非常的简单 , 之前我们已经体验过了 , 那么删除一个文件也同样的简单 , 代码示例如下:
Files.delete(file);Files.deleteIfExists(file);使用 Files.delete() 删除文件之前最好使用 Files.exists() 判断文件是否存在 , 否则会抛出 NoSuchFileException;Files.deleteIfExists() 则不用 。
复制文件也不复杂 , 代码示例如下:
Path source = Paths.get("沉默王二.txt");Path target = Paths.get("沉默王二1.txt");Files.copy(source, target);移动文件和复制文件非常相似 , 代码示例如下:
Path source = Paths.get("沉默王二.txt");Path target = Paths.get("沉默王二1.txt");Files.move(source, target);05、快速地读写文件
NIO 2.0 提供了带有缓冲区的读写辅助方法 , 使用起来也非常的简单 。可以通过 Files.newBufferedWriter() 获取一个文件缓冲输入流 , 并通过 write() 方法写入数据;然后通过 Files.newBufferedReader() 获取一个文件缓冲输出流 , 通过 readLine() 方法读出数据 。代码示例如下 。
Path file = Paths.get("沉默王二.txt");try (BufferedWriter writer = Files.newBufferedWriter(file, StandardCharsets.UTF_8)) { writer.write("一个有趣的程序员");} catch (Exception e) { e.printStackTrace();}try (BufferedReader reader = Files.newBufferedReader(file, StandardCharsets.UTF_8)) { String line; while ((line = reader.readLine()) != null) { System.out.println(line); }} catch (Exception e) { e.printStackTrace();}06、重要:异步 I/O 操作
实话实说吧 , 上面提到的那些都算是 NIO 2.0 的甜点 , 而异步 I/O 操作(也称 AIO)才算是真正重要的内容 。异步 I/O 操作可以充分利用多核 CPU 的特点 , 不需要再像以前那样启动一个线程来对 I/O 进行处理 , 免得阻塞了主线程的其他操作 。
异步 I/O 操作的核心概念是发起非阻塞方式的 I/O 操作 , 当 I/O 操作完成时通知 。可以分为两种形式:Future 和 Callback 。如果我们希望主线程发起 I/O 操作并轮循等待结果时 , 一般使用 Future 的形式;而 Callback 的基本思想是主线程派出一个侦查员(CompletionHandler)到独立的线程中执行 I/O 操作 , 操作完成后 , 会触发侦查员的 completed 或者 failed 方法 。
1)Future
先来看一个示例 , 代码如下:
public static void main(String[] args) throws IOException, InterruptedException, ExecutionException { Path file = Paths.get("沉默王二.txt"); AsynchronousFileChannel channel = AsynchronousFileChannel.open(file); Future<Integer> result = channel.read(ByteBuffer.allocate(100_000), 0); while (!result.isDone()) { System.out.println("主线程继续做事情"); } Integer bytesRead = result.get(); System.out.println(bytesRead);}1)通过 AsynchronousFileChannel.open() 打开一个异步文件通道 channel 。
2)用 Future 来保存从通道中读取的结果 。
3)通过 isDone() 轮循判断异步 I/O 操作是否完成 , 如果没有完成的话 , 主线程可以继续做自己的事情 。
2)Callback
先来看一个示例 , 代码如下:
public static void main(String[] args) throws IOException, InterruptedException, ExecutionException { Path file = Paths.get("沉默王二.txt"); AsynchronousFileChannel channel = AsynchronousFileChannel.open(file); channel.read(ByteBuffer.allocate(100_000), 0, null, new CompletionHandler<Integer, ByteBuffer>() { public void completed(Integer result, ByteBuffer attachment) { System.out.println(result); } public void failed(Throwable exc, ByteBuffer attachment) { System.out.println(exc.getMessage()); } }); System.out.println("主线程继续做事情");}1)通过 AsynchronousFileChannel.open() 打开一个异步文件通道 channel 。


推荐阅读