在Java 7,AsynchronousFileChannel 被添加到了Java NIO中。使用AsynchronousFileChannel可以实现异步地读取和写入文件数据。

创建一个AsynchronousFileChannel

我们可以使用AsynchronousFileChannel提供的静态方法 open() 创建它。示例代码如下:

Path path = Paths.get("data/test.xml");
AsynchronousFileChannel fileChannel =
AsynchronousFileChannel.open(path, StandardOpenOption.READ);

第一个参数是一个 PATH 的对像实例,它指向了那个与 AsynchronousFileChannel 相关联的文件。

第二个参数是一个或多个操作选项,它决定了 AsynchronousFileChannel 将对目标文件做何种操作。示例代码中我们使用了 StandardOpenOption.READ ,它表明我们将要对目标文件进行读操作。

读取数据

AsynchronousFileChannel 提供了两种读取数据的方式,都是调用它本身的 read() 方法。下面将对两种方式进行介绍。

使用Futrue读取数据

第一种反式是调用 AsynchronousFileChannel 的 read() 方法,该方法反回一个 Future 类型的对象。

Future operation = fileChannelread(buffer, 0);

第一个参数是ByteBuffer,从 AsynchronousFileChannel 中读取的数据先写入这个 ByteBuffer 。

第二个参数表示从文件读取数据的开始位置。

此 read() 方法会立即返回,即使整个读的过程还没有完全结束。我们可以通过operation.isDone()来检查读取是否完成。这里的 operation 是上面调用 read() 方法返回的 Future 类型的实例。下面是一段详细的代码示例:

AsynchronousFileChannel fileChannel =
AsynchronousFileChannel.open(path, StandardOpenOption.READ); ByteBuffer buffer = ByteBuffer.allocate(1024);
long position = 0; Future<Integer> operation = fileChannel.read(buffer, position); while(!operation.isDone()); buffer.flip();
byte[] data = new byte[buffer.limit()];
buffer.get(data);
System.out.println(new String(data));
buffer.clear();

上面的程序首先创建了一个 AsynchronousFileChannel 对象,然后调用它的read()方法返回一个Future。其中read()方法需要两个参数,一个是ByteBuffer,另一个是读取文件的开始位置。然后通过循环调用isDone() 方法检测读取过程是否完成,完成后 isDone()方法将返回true。尽管这样让cpu空转了一会,但是我们还是应该等读取操作完成后再进行后续的步骤。

一旦读取完成,数据被存储到ByteBuffer,然后将数据转化为字符串既而输出。

使用CompletionHandler读取数据

第二种读取数据的方式是调用AsynchronousFileChannel 的另一个重载 read() 方法,改方法需要一个CompletionHandler 作为参数。下面是代码示例:

fileChannel.read(buffer, position, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
System.out.println("result = " + result); attachment.flip();
byte[] data = new byte[attachment.limit()];
attachment.get(data);
System.out.println(new String(data));
attachment.clear();
} @Override
public void failed(Throwable exc, ByteBuffer attachment) { }
});

一旦读取操作完成,CompletionHandler的 complete() 方法将会被调用。它的第一个参数是个 Integer类型,表示读取的字节数。第二个参数 attachment 是 ByteBuffer 类型的,用来存储读取的数据。它其实就是由 read() 方法的第三个参数。当前示例中,我们选用 ByteBuffer 来存储数据,其实我们也可以选用其他的类型。

读取失败的时候,CompletionHandler的 failed()方法会被调用。

写入数据

就像读取一样,我们同样有两种方式向 AsynchronousFileChannel 写入数据。我们可以调用它的2个重载的 write() 方法。下面我们将分别加以介绍。

使用Future读取数据

AsynchronousFileChannel也可以异步写入数据。下面是一个完整的写入示例:

Path path = Paths.get("data/test-write.txt");
AsynchronousFileChannel fileChannel =
AsynchronousFileChannel.open(path, StandardOpenOption.WRITE); ByteBuffer buffer = ByteBuffer.allocate(1024);
long position = 0; buffer.put("test data".getBytes());
buffer.flip(); Future<Integer> operation = fileChannel.write(buffer, position);
buffer.clear(); while(!operation.isDone()); System.out.println("Write done");

首先实例化一个写入模式的 AsynchronousFileChannel, 然后创建一个 ByteBuffer 并写入一些数据。再然后将数据写入文件。最后,检查返回的 Future,看是否写入完成。

注意,写入目标文件要提前创建好,如果它不存在的话,writh() 方法会抛出一个 java.nio.file.NoSuchFileException。

我们可以用以下方式来解决这一问题:

if(!Files.exists(path)){
Files.createFile(path);
}

使用CompletionHandler写入数据

我们也可以使用 CompletionHandler代替Future向AsynchronousFileChannel写入数据,这种方式可以更加直接的知道写入过程是否完成。下面是示例程序:

Path path = Paths.get("data/test-write.txt");
if(!Files.exists(path)){
Files.createFile(path);
}
AsynchronousFileChannel fileChannel =
AsynchronousFileChannel.open(path, StandardOpenOption.WRITE); ByteBuffer buffer = ByteBuffer.allocate(1024);
long position = 0; buffer.put("test data".getBytes());
buffer.flip(); fileChannel.write(buffer, position, buffer, new CompletionHandler<Integer, ByteBuffer>() { @Override
public void completed(Integer result, ByteBuffer attachment) {
System.out.println("bytes written: " + result);
} @Override
public void failed(Throwable exc, ByteBuffer attachment) {
System.out.println("Write failed");
exc.printStackTrace();
}
});

当写入程序完成时,CompletionHandler的completed()方法将会被调用,相反的如果写入失败则会调用failed()方法。

要留意CompletionHandler的方法的参数 attachemnt是怎么使用的。

最后

私信回复 资料 领取一线大厂Java面试题总结+阿里巴巴泰山手册+各知识点学习思维导+一份300页pdf文档的Java核心知识点总结!

这些资料的内容都是面试时面试官必问的知识点,篇章包括了很多知识点,其中包括了有基础知识、Java集合、JVM、多线程并发、spring原理、微服务、Netty 与RPC 、Kafka、日记、设计模式、Java算法、数据库、Zookeeper、分布式缓存、数据结构等等。

异步文件通道Java NIO你需要了解多少,来看看这篇文章的更多相关文章

  1. Java NIO 学习笔记(六)----异步文件通道 AsynchronousFileChannel

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

  2. springcloud采坑--Zuul上传文件报java.nio.charset.IllegalCharsetNameException: UTF-8;boundary=sqgzzmMxl1UPdIp0IAYnQgUIAr9yNewVAzKIX

    报错日志: 2018-12-17 10:01:19,688 ERROR [io.undertow.request] (default task-3) UT005023: Exception handl ...

  3. 再有人问你Java内存模型是什么,就把这篇文章发给他

    前几天,发了一篇文章,介绍了一下JVM内存结构.Java内存模型以及Java对象模型之间的区别.有很多小伙伴反馈希望可以深入的讲解下每个知识点.Java内存模型,是这三个知识点当中最晦涩难懂的一个,而 ...

  4. 可能是把Java内存区域讲的最清楚的一篇文章

    写在前面(常见面试题) 下面是面试官可能在“Java内存区域”知识点问你的问题,快拿出小本本记下来! 基本问题: 介绍下Java内存区域(运行时数据区). Java对象的创建过程(五步,建议能默写出来 ...

  5. [No0000187]可能是把Java内存区域讲的最清楚的一篇文章

    写在前面(常见面试题) 基本问题: 介绍下 Java 内存区域(运行时数据区) Java 对象的创建过程(五步,建议能默写出来并且要知道每一步虚拟机做了什么) 对象的访问定位的两种方式(句柄和直接指针 ...

  6. 可能是把 Java 内存区域讲的最清楚的一篇文章

    出处:  可能是把 Java 内存区域讲的最清楚的一篇文章 Java 内存区域详解 写在前面 (常见面试题) 基本问题 拓展问题 一 概述 二 运行时数据区域 2.1 程序计数器 2.2 Java 虚 ...

  7. 这应该是把Java内存区域讲的最清楚的一篇文章

    基本问题: 介绍下 Java 内存区域(运行时数据区) Java 对象的创建过程(五步,建议能默写出来并且要知道每一步虚拟机做了什么) 对象的访问定位的两种方式(句柄和直接指针两种方式) 拓展问题: ...

  8. Java NIO 学习

    Java NIO提供了与标准IO不同的IO工作方式: Channels and Buffers(通道和缓冲区):标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(B ...

  9. [转]Java NIO通俗易懂简明教程

    Java NIO(New IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API.本系列教程将有助于你学习和理解Java NIO. Java NIO提供了与 ...

随机推荐

  1. Maven 专题(五):Maven核心概念详解(一)

    **Maven 的核心程序中仅仅定义了抽象的生命周期,而具体的操作则是由 Maven 的插件来完成的.**可是 Maven 的插件并不包含在 Maven 的核心程序中,在首次使用时需要联网下载. 下载 ...

  2. CSS定位布局

    CSS定位布局 基础知识 在CSS布局中,定位布局也是一种非常常见的技术手段,我们以京东为例: 上面是非常好的例子,对于定位布局来说它可以将一个元素放在页面上的任意一个位置. 但是定位布局也不能滥用, ...

  3. python+requests实现接口自动化

    1. 前言 今年2月调去支持项目接口测试,测试过程中使用过postman.jmeter工具,基本能满足使用,但是部分情况下使用较为麻烦.比如:部分字段存在唯一性校验或字段间有业务性校验,每次请求均需手 ...

  4. OSCP Learning Notes - Buffer Overflows(2)

    Finding the Offset 1. Use the Metasploite pattern_create.rb tool to create 5900 characters. /usr/sha ...

  5. “git pull” 强制覆盖本地文件

    放弃本地修改,使用服务器代码覆盖本地的Git命令如下: $ git fetch --all $ git reset --hard origin/master $ git pull 使用master分支 ...

  6. vue 表格使用el-select

    <el-table-column label="示例" width="210" align="center"> <temp ...

  7. 在 CentOS 7(Linux)上部署ASP.NET Core 2.2 Web应用程序(Tengine、Asp.Net Core MVC、Centos 7、MySql)

    一.前言 1.简单记录一下Linux CentOS 7中安装与配置Tengine的详细步骤. 2.简单比较一下Tengine 和Nginx 3.搭建Asp.net Core和部署 Web程序 4.总结 ...

  8. Angular 的前世今生

    目录 序言 AngularJS 简介 Angular 2.0 的动机 现如今的 Angular Angular 的核心概念 参考 序言 Angular 一般意义上是指 Angular v2 及以上版本 ...

  9. 高效C++:实现

    本章主要是解决如下问题: 类的声明和定义在什么时候提出 类与类之间的耦合关系如何降低 类型转换怎么正确使用 尽可能延后变量定义式的出现 变量用到时在定义,不要提前定义,防止变量定义而没有使用的情况,因 ...

  10. ES模糊查询来对应mysql的like查询

    使用ES查询来对应mysql的like查询 建立一个测试索引 PUT /test_like1 { "mappings" : { "properties" : { ...