NIO之通道Channel【FileChannel介绍】

简介: 通道(channel)介绍 Channel是一个对象,作用是用于源节点和目标节点的连接,在java NIO中负责缓冲区数据的传递。Channel本身不存储数据,因此需要配合缓冲区进行传输。


通道(channel)介绍

 Channel是一个对象,作用是用于源节点和目标节点的连接,在java NIO中负责缓冲区数据的传递。Channel本身不存储数据,因此需要配合缓冲区进行传输。

image.png

主要的实现类有

 主要的实现类有如下四个: FileChannel, SocketChannel, ServerSocketChannel, DatagramChannel,都实现了java.nio.channels.Channel接口

image.png

获取通道

   Java针对支持通道的类提供了getChannel()方法

image.png

   在JDK1.7中的NIO.2针对各个通道提供了静态方法open()

   在JDK1.7中的NIO.2的Files工具类的newByteChannel()

public static void main(String[] args) throws Exception {
  // 1本地IO获取通道
  FileInputStream in = new FileInputStream("c:/tools/a.txt");
  FileChannel fileChannel = in.getChannel();
  // 2.通过open方法获取
  FileChannel.open(Paths.get("c:/tools/a.txt"), StandardOpenOption.READ);
}

 

案例-文件复制

1.使用FileChannel配合缓冲区实现文件复制的功能

/**
 * FileChannel实现文件复制功能
 * @param args
 * @throws Exception 
 */
public static void main(String[] args) throws Exception {
  FileInputStream in = new FileInputStream("c:/tools/a.txt");
  FileOutputStream out = new FileOutputStream("c:/tools/a-copy1.txt");
  FileChannel inChannel = in.getChannel();
  FileChannel outChannel = out.getChannel();
  // 分配指定大小的缓冲区
  ByteBuffer bb = ByteBuffer.allocate(1024);
  // 将通道中的数据存入缓冲区中
  while(inChannel.read(bb)!=-1){
    bb.flip();// 切换到读取模式
    outChannel.write(bb); // 将缓冲区的数据写入到输出通道中
    bb.clear(); // 清空缓冲区
  }
  outChannel.close();
  inChannel.close();
}

2.内存映射文件的方式实现文件复制

/**
 * 使用直接缓冲区来完成文件的复制【内存映射文件】
 * @param args
 * @throws Exception
 */
public static void main(String[] args) throws Exception {
  FileChannel inChannel = FileChannel.open(Paths.get("c:/tools/a.txt"),StandardOpenOption.READ );
  FileChannel outChannel = FileChannel.open(
        Paths.get("c:/tools/aa.txt")
        , StandardOpenOption.WRITE
        ,StandardOpenOption.CREATE
        ,StandardOpenOption.READ);
  // 获取内存映射文件
  MappedByteBuffer inMap = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());
  MappedByteBuffer outMap = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size());    
  byte[] b = new byte[inMap.limit()];
  // 从磁盘文件中获取数据写入到b字节数组中
  inMap.get(b);
  // 将b字节数组中的数据写入到磁盘文件中
  outMap.put(b);
  inChannel.close();
  outChannel.close();
}

3.Channel-to-channel方式实现复制

/**
 * 使用直接缓冲区来完成文件的复制【内存映射文件】
 * @param args
 * @throws Exception
 */
public static void main(String[] args) throws Exception {
  FileChannel inChannel = FileChannel.open(Paths.get("c:/tools/a.txt"),StandardOpenOption.READ );
  FileChannel outChannel = FileChannel.open(
        Paths.get("c:/tools/aa1.txt")
        ,StandardOpenOption.WRITE
        ,StandardOpenOption.CREATE
        ,StandardOpenOption.READ);
  //Channel-to-channel 传输是可以极其快速的,特别是在底层操作系统提供本地支持的时候。某些
  //操作系统可以不必通过用户空间传递数据而进行直接的数据传输。对于大量的数据传输,这会是一个巨大的帮助
  inChannel.transferTo(0, inChannel.size(), outChannel);
  inChannel.close();
  outChannel.close();
}

scatter和gather

分散(scatter)

 从Channel中读取是指在读操作时将读取的数据写入多个buffer中,将从Channel中读取的数据“分散(scatter)”到多个Buffer中

image.png

/**
 * 分散:scatter
 * @param args
 * @throws IOException 
 */
public static void main(String[] args) throws IOException {
  FileChannel channel = FileChannel.open(Paths.get("c:/tools/a.txt"), StandardOpenOption.READ);
  // TODO Auto-generated method stub
  ByteBuffer header = ByteBuffer.allocate(16);
  ByteBuffer body   = ByteBuffer.allocate(1024);
  ByteBuffer[] bufferArray = { header, body };
  channel.read(bufferArray);
  bufferArray[0].flip();
  bufferArray[1].flip();
  System.out.println(new String(bufferArray[0].array(),0,bufferArray[0].limit()));
  System.out.println("---------");
  System.out.println(new String(bufferArray[1].array(),0,bufferArray[1].limit()));
}

   注意buffer首先被插入到数组,然后再将数组作为channel.read() 的输入参数。read()方法按照buffer在数组中的顺序将从channel中读取的数据写入到buffer,当一个buffer被写满后,channel紧接着向另一个buffer中写。

   Scattering Reads在移动下一个buffer前,必须填满当前的buffer,这也意味着它不适用于动态消息(译者注:消息大小不固定)。换句话说,如果存在消息头和消息体,消息头必须完成填充(例如 128byte),Scattering Reads才能正常工作。

聚集(gather)

 写入Channel是指在写操作时将多个buffer的数据写入同一个Channel, 将多个Buffer中的数据“聚集(gather)”后发送到Channel

image.png

/**
 * 聚集gether
 * @param args
 * @throws IOException 
 */
public static void main(String[] args) throws IOException {
  FileChannel channel = FileChannel.open(Paths.get("c:/tools/ag.txt"), StandardOpenOption.WRITE);
  ByteBuffer header = ByteBuffer.allocate(128);
  ByteBuffer body   = ByteBuffer.allocate(1024);
  // 写入内容
  header.put("bobo".getBytes());
  // 转换为读模式
  header.flip();
  // 写入内容
  body.put("hello".getBytes());
  // 转换为读模式
  body.flip();
  //write data into buffers
  ByteBuffer[] bufferArray = { header, body };
  // 将这两个缓冲区的数据依次写入到文件中
  channel.write(bufferArray);
}

   buffers数组是write()方法的入参,write()方法会按照buffer在数组中的顺序,将数据写入到channel,注意只有position和limit之间的数据才会被写入。因此,如果一个buffer的容量为128byte,但是仅仅包含58byte的数据,那么这58byte的数据将被写入到channel中。因此与Scattering Reads相反,Gathering Writes能较好的处理动态消息。


相关文章
|
6月前
|
存储 编解码 移动开发
技术笔记:NIO流—理解Buffer、Channel概念和NIO的读写操作
技术笔记:NIO流—理解Buffer、Channel概念和NIO的读写操作
41 1
|
7月前
|
缓存 网络协议 Java
📌 Java NIO Channel
Java NIOChannel和传统的流相似,但是也存在一些差异: • 在同一个Channel通道中,既可以进行 读操作 也可以进行 写操作,但是 流 只能进行 读 或者 写 其中一种操作。 • Channel通道可以进行异步读写。 • Channel可以从 Buffer中进行读写操作。将数据从Channel通道读取到Buffer缓冲区,并将数据从Buffer缓冲区写入Channel通道。
|
7月前
|
存储 网络协议 Java
NIO - 基础入门之通道和缓冲区
NIO - 基础入门之通道和缓冲区
87 0
|
存储 网络协议 Java
Netty入门到超神系列-Java NIO 三大核心(selector,channel,buffer)
选择器,也叫多路复用器,Java的NIO通过selector实现一个线程处理多个客户端链接,多个channel可以注册到同一个Selector,Selector能够监测到channel上是否有读/写事件发生,从而获取事件和对事件进行处理,所以Selector切到哪个channel是由事件决定的。当线程从某个客户端通道未读取到数据时,可以把空闲时间用来做其他任务,性能得到了提升。
156 0
|
弹性计算 Java API
Netty入门到超神系列-Java NIO 三大核心(selector,channel,buffer)
理解Selector 和 Channel Selector 选择器,也叫多路复用器,可以同时处理多个客户端连接,多路复用器采用轮询机制来选择有读写事件的客户端链接进行处理。 通过 Selector ,一个 I/O 线程可以并发处理 N 个客户端连接和读写操作,这解决了传统同步阻塞 I/O 一连接一线程模型,架构的性能、弹性伸缩能力和可靠性都得到了极大的提升。 由于它的读写操作都是非阻塞的,这就可以充分提升 IO 线程的运行效率,避免由于频繁 I/O 阻塞导致的线程挂起。
259 0
|
网络协议 前端开发 Java
Netty异步NIO框架(一)java服务端与客户端实现聊天 websocket通道
Netty异步NIO框架(一)java服务端与客户端实现聊天 websocket通道
|
缓存 网络协议 Java
Java NIO学习(二):Channel通道
Java NIO 的通道类似流,但又有些不同:
170 0
Java NIO学习(二):Channel通道
|
Java API
NIO学习三-Channel
在学习NIO时,ByteBuffer、Channel、Selector三个组件是必须了解的。前面我们说到ByteBuffer是作为缓冲区进行数据的存放或者获取。通常我们需要进行flip翻转操作,但是这个在Netty中,有一个更为强大的类可以替代ByteBuf,其不需要进行翻转,也可以进行读写的双向操作。要将数据打包到缓冲区中,通常需要使用通道,而通道作为传输数据的载体,也即它可以使数据从一端到另一端,因此就必须进行了解。 Channel中,我们也看到其子类有很多,通常都是用于读写操作的。其中ByteChannel可以进行读写操作,也即可以进行双向操作。 操作过程:首先创建流对象,有了流对象获取
87 0
NIO学习三-Channel
java Nio (四) :通道(Channel)
java Nio (四) :通道(Channel)
|
安全 Java
Java 堆外内存、零拷贝、直接内存以及针对于NIO中的FileChannel的思考(下)
Java 堆外内存、零拷贝、直接内存以及针对于NIO中的FileChannel的思考(下)
Java 堆外内存、零拷贝、直接内存以及针对于NIO中的FileChannel的思考(下)