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。
2)在 read 方法中使用匿名内部类的形式启用 CompletionHandler,然后实现 CompletionHandler 的两个监听方法,completed 的时候打印结果,failed 的时候打印异常信息。
不管是 Future 形式还是 Callback 形式,总之异步 I/O 是一个强大的特性,可以保证在处理大文件时性能不受到显著的影响。