通道(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. POJ 3168 Barn Expansion (几何基础)

    [题目链接] http://poj.org/problem?id=3168 [题目大意] 给出一些矩形,没有相交和包含的情况,只有相切的情况 问有多少个矩形没有相切或者边角重叠 [题解] 我们将所有的 ...

  2. Mybatis添加&&删除&&更新

    mapper <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC & ...

  3. ionic 打包成apk后,所有网络请求404

    无论怎么改 config.xml <allow-navigation href="http://*/*" /> <allow-intent href=" ...

  4. 推荐一些不错的开源免费易上手的web前端框架

    1. bui 2.Semantic UI 3.oniui

  5. 如何提高码农产量,基于ASP.NET MVC的敏捷开发框架之自定义表单开发随笔四

    “厂长,上一次我们讲过了工作流的整体规划,今天我要动手做啦!我想先把工作流的自定义表单做出来.” “好的,以前我做这方面的东西,我给你设计了一份表结构,你先拿去看看.” “厂长,是不是没发完,怎么就一 ...

  6. 《新一代视频压缩码标准-H.264_AVC》读书笔记1

    摘要 第一章 绪论 正文 1.一般而言,视频信号信息量大,传输网络所需要的带宽相对较宽.例如,一路可视电话或会议电视信号,由于其活动内容较少,所需带宽较窄,但要达到良好质量,不压缩约需若干 Mbps, ...

  7. 阿里p6面试

    电话面试: 第一次面试关注的问题,1)java基础: jvm 内存回收,垃圾回收基本原理,Java并发包的线程池,Java8的新特性.nio 堆排序.conrenthashmap , concurre ...

  8. 【java】服务器端获取用户访问的URL/用户IP/PC还是移动端

    @RequestMapping(value="/test") @ResponseBody public void test1(HttpServletRequest request, ...

  9. Linq 简明教程

    一个简单的实例 static void Main(string[] args) { string[] names = { "Alonso", "Zheng", ...

  10. Javascript高级程序设计-问答模式

    1.谈谈javascript数组排序方法sort()的使用,重点介绍sort()参数的使用及其内部机制 sort的实现的功能类似JAVA的比较器,数据排序从多维数组的第一维开始排序可以自己定义排序方法 ...