通道(Channel)

  由java.nio.channels包定义的,Channel表示IO源与目标打开的连接,Channel类似于传统的“流”,只不过Channel本身不能直接访问数据,Channel只能与Buffer进行交互。通道主要用于传输数据,从缓冲区的一侧传到另一侧的实体(如文件、套接字...),反之亦然;通道是访问IO服务的导管,通过通道,我们可以以最小的开销来访问操作系统的I/O服务;顺便说下,缓冲区是通道内部发送数据和接收数据的端点。

  在标准的IO当中,都是基于字节流/字符流进行操作的,而在NIO中则是是基于Channel和Buffer进行操作,其中的Channel的虽然模拟了流的概念,实则大不相同。

区别 Stream Channel
支持异步 不支持 支持
是否可双向传输数据 不能,只能单向 可以,既可以从通道读取数据,也可以向通道写入数据
是否结合Buffer使用 必须结合Buffer使用
性能 较低 较高

传统与革新

传统的数据流:
CPU处理IO,性能损耗太大
改为:
内存和IO接口之间加了 DMA(直接存储器),DMA向CPU申请权限,IO的操作全部由DMA管理。CPU不要干预。
若有大量的IO请求,会造成DMA的走线过多,则也会影响性能。
则改DMA为Channel,Channel为完全独立的单元,不需要向CPU申请权限,专门用于IO。
 

早一代IO操作是由CPU负责IO接口

新一代DMA授权处理IO接口

通道(Channel)模式

Channel的实现类

java.nio.channels.Channel 接口:
|-- FileChannel
|-- SocketChannel
|-- ServerSocketChannel
|-- DatagramChannel

获取通道Channel

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

本地IO

  • FileInputStream/FileOutputStream
  • RandomAccessFile

网络IO

  • Socket
  • ServerSocket
  • DatagramSocket

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

FileChannel.open(Paths.get("d:\\xxx.jpg"), StandardOpenOption.READ);

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

Files.newByteChannel(filePath)

通道之间的数据传输

transferFrom()
transferTo()

StandardOpenOption介绍

在打开文件通道时可以选择的选项有很多,其中最常见的是读取和写入模式的选择,分别通过java.nio.file.StandardOpenOption枚举类型中的READ和WRITE来声明。

  1. CREATE表示当目标文件不存在时,需要创建一个新文件;
  2. CREATE_NEW同样会创建新文件,区别在于如果文件已经存在,则会产生错误;
  3. APPEND表示对文件的写入操作总是发生在文件的末尾处,即在文件的末尾添加新内容;
  4. 当声明了TRUNCATE_EXISTING选项时,如果文件已经存在,那么它的内容将被清空;
  5. DELETE_ON_CLOSE用在需要创建临时文件的时候,声明了这个选项之后,当文件通道关闭时,Java虚拟机会尽力尝试去删除这个文件。

代码示例

 package com.expgiga.NIO;

 import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption; /**
* Channel:用于源节点与目标节点之间的连接。在Java NIO中,负责缓冲区中数据传输,Channel本身不存储数据,因此需要配合缓冲区进行传输。
*
*
*/
public class TestChannel { public static void main(String[] args) throws IOException { /*
* 1.利用通道完成文件的复制(非直接缓冲区)
*/
FileInputStream fis = null;
FileOutputStream fos = null; FileChannel inChannel = null;
FileChannel outChannel = null; try {
fis = new FileInputStream("1.jpg");
fos = new FileOutputStream("2.jpg");
//1.获取通道
inChannel = fis.getChannel();
outChannel = fos.getChannel(); //2.分配指定大小的缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024); //3.将通道中的数据缓冲区中
while (inChannel.read(buffer) != -1) { buffer.flip();//切换成都数据模式 //4.将缓冲区中的数据写入通道中
outChannel.write(buffer);
buffer.clear();//清空缓冲区
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (outChannel != null) {
try {
outChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
} if (inChannel != null) {
try {
inChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
} if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
} if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} /*
* 2.利用(直接缓冲区)通道完成文件的复制(内存映射文件的方式)
*/
      
long start = System.currentTimeMillis();
FileChannel inChannel2 = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
FileChannel outChannel2 = FileChannel.open(Paths.get("3.jpg"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE); //内存映射文件
MappedByteBuffer inMappedBuf = inChannel2.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
MappedByteBuffer outMappedBuf = outChannel2.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size()); //直接对缓冲区进行数据读写操作
byte[] dst = new byte[inMappedBuf.limit()];
inMappedBuf.get(dst);
outMappedBuf.put(dst); inChannel2.close();
outChannel2.close(); long end = System.currentTimeMillis();
System.out.println("耗费的时间为:" + (end - start)); /*
* 通道之间的数据传输(直接缓冲区)
*/
FileChannel inChannel3 = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
FileChannel outChannel3 = FileChannel.open(Paths.get("3.jpg"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE); inChannel3.transferTo(0, inChannel3.size(), outChannel3);
//等价于
// outChannel3.transferFrom(inChannel3, 0, inChannel3.size()); inChannel3.close();
outChannel3.close();
}
}

结果比较

我复制的文件大小为312MB

io time:2685
nio channel time:1129
nio buffer time:601

说明nio操作缓冲区是最快的。

NIO之通道(Channel)的原理与获取以及数据传输与内存映射文件的更多相关文章

  1. 通道(Channel)的原理与获取

    通道(Channel):由 java.nio.channels 包定义 的.Channel 表示 IO 源与目标打开的连接. Channel 类似于传统的“流”.只不过 Channel 本身不能直接访 ...

  2. Java-NIO(五):通道(Channel)的数据传输与内存映射文件

    通道(Channel)的数据传输(采用非直接缓冲区) @Test public void testChannel() throws IOException { FileInputStream file ...

  3. Java-NIO(四):通道(Channel)的原理与获取

    通道(Channel): 由java.nio.channels包定义的,Channel表示IO源与目标打开的连接,Channel类似于传统的“流”,只不过Channel本身不能直接访问数据,Chann ...

  4. JAVA NIO之浅谈内存映射文件原理与DirectMemory

    JAVA类库中的NIO包相对于IO 包来说有一个新功能是内存映射文件,日常编程中并不是经常用到,但是在处理大文件时是比较理想的提高效率的手段.本文我主要想结合操作系统中(OS)相关方面的知识介绍一下原 ...

  5. 【NIO】NIO之浅谈内存映射文件原理与DirectMemory

    Java类库中的NIO包相对于IO 包来说有一个新功能是内存映射文件,日常编程中并不是经常用到,但是在处理大文件时是比较理想的提高效率的手段.本文我主要想结合操作系统中(OS)相关方面的知识介绍一下原 ...

  6. Java NIO 内存映射文件

    Java NIO 内存映射文件 @author ixenos 文件操作的四大方法 前提:内存的访问速度比磁盘高几个数量级,但是基本的IO操作是直接调用native方法获得驱动和磁盘交互的,IO速度限制 ...

  7. Java NIO之内存映射文件——MappedByteBuffer

    大多数操作系统都可以利用虚拟内存实现将一个文件或者文件的一部分"映射"到内存中.然后,这个文件就可以当作是内存数组来访问,这比传统的文件要快得多. 内存映射文件的一个关键优势是操作 ...

  8. 【JavaNIO的深入研究4】内存映射文件I/O,大文件读写操作,Java nio之MappedByteBuffer,高效文件/内存映射

    内存映射文件能让你创建和修改那些因为太大而无法放入内存的文件.有了内存映射文件,你就可以认为文件已经全部读进了内存,然后把它当成一个非常大的数组来访问.这种解决办法能大大简化修改文件的代码.fileC ...

  9. 通道(Channel)的原理获取

    通道表示打开到 IO 设备(例如:文件.套接字)的连接.若需要使用 NIO 系统,需要获取用于连接 IO 设备的通道以及用于容纳数据的缓冲区.然后操作缓冲区,对数据进行处理.Channel 负责传输, ...

随机推荐

  1. KMP+差分 文章过滤器 (filter)

    Description 给定一些短串,要求你在一个长串中,将这些短串部分变为\(*\) Input 第一行包括一个整数\(n\),表示短串的数量. 接下来的\(n\)行,为\(n\)个短串. 最后一行 ...

  2. Proxy(2016山东省省赛C)(最短路)(spfa)

    问题 C: Proxy 时间限制: 2 Sec  内存限制: 128 MB提交: 17  解决: 5[提交][状态][讨论版] 题目描述 Because of the GFW (Great Firew ...

  3. APP换肤

    一.需求说明 当一个APP用户量大的时候,就需要给不同的用户做标签,用来彰显身份.比如QQ的会员,VIP等不同的皮肤功能. 二.实现方法. 所谓不同的皮肤,就是不同的权限(身份)显示不同的本地或者网络 ...

  4. 理解XML-RPC

    有关XML-RPC http://baike.baidu.com/link?url=ejidFtjelUzPv75VBm5_XrzSbHtFgArYY47S1s1NK2_m-auOr10sTeRh6U ...

  5. [USACO06DEC] Milk Patterns

    题目描述 Farmer John has noticed that the quality of milk given by his cows varies from day to day. On f ...

  6. [CF865C]Gotta Go Fast

    题目大意: 一个游戏关卡有$n(n\le50)$个任务,若在$m$秒内按顺序完成所有任务则算作通过当前关卡.每个关卡有三个属性$a_i,b_i,p_i(1\le a_i<b_i\le100,80 ...

  7. RabbitMQ技术详解(转)

    RabbitMQ是什么 定义 RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python.Ruby..NET.Java.JMS.C.PHP.Action ...

  8. JS删除数组中某一项或几项的方法汇总

    1.JS中的splice方法 splice(index, len, [item])    //注意:该方法会改变原始数组. splice有3个参数,它也可以用来替换/删除/添加数组内某一个或者几个值. ...

  9. 浅谈RBF函数

    所谓径向基函数 (Radial Basis Function 简称 RBF), 就是某种沿径向对称的标量函数. 通常定义为空间中任一点x到某一中心xc之间欧氏距离的单调函数 , 可记作 k(||x-x ...

  10. 关于java的关键字 transient

    我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,Java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过程,只要这个类实现了Serilizable ...