zoukankan      html  css  js  c++  java
  • 3.通道 Channel

    一、通道(Channel):由java.nio.channels包定义的 。Channel 表示 IO 源与目标打开的连接。

    Channel 类似于传统的 ‘流’。只不过 Channel 本身不能直接访问数据,Channel只能与Buffer进行交互

    二、 /*通道的主要实现类*/

    Java 为 Channel 接口提供的 最主要实现类如下:

      FileChannel:用于读取、写入、映射和操作文件的通道

      SocketChannel:通过TCP 读写网络中的数据

      ServerSocketChannel:可以监听新进来的TCP连接,对每一个新进来的连接都会创建一个 SocketChannel

    三、 /*如何获取通道*/

    获取通道

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

        * 本地IO:

          * FileInputStream/FileOutputStream

          * RandomAccessFile


        * 网络IO:

          * Socket

          * ServerSocket

          * DatagramSocket


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

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

    利用通道进行数据传输


    四、 /*通道之间的数据传输*/

      transferForm() 将数据从源通道 传输到其他 Channel中

      transferTo() 其他 Channel 从 原通道中 获取数据

      

    五、 /*分散(Scatter) 与 聚集(Gather)*/

      分散读取(Scattering Reads):将通道中的数据分散到多个缓冲区

      聚集写入(Gathering Writes):将多个缓冲区中的 数据 聚集到通道中

      
    六、 /*字符集:Charset*/

      编码:字符串 -> 字节数组

      解码: 字节数组 -> 字符串
      

      1 /*
      2  * 一、通道(Channel):用于源节点 与目标节点的连接 ,在java nio 中 负责缓冲区中数据的传输。Channel 本身不存储数据,因此需要配合缓冲区进行传输
      3  * 
      4  * 二、通道的主要实现类
      5  *     java.nio.channels.Channel 接口
      6  *         |--FileChannel
      7  *         |--SocketChannel
      8  *         |--ServerSocketChannel
      9  *         |--DatagramChannel
     10  * 
     11  * 三、获取通道
     12  * 1.Java针对 支持通道的类提供了 getChannel()方法
     13  *      本地IO:
     14  *      FileInputStream/FileOutputStream
     15  *      RandomAccessFile
     16  * 
     17  *   网络IO:
     18  *   Socket
     19  *   ServerSocket
     20  *   DatagramSocket
     21  *  
     22  * 2.在 JDK1.7 中 的 NIO.2 针对各个通道提供了静态方法 open()
     23  * 
     24  * 3.在 JDK1.7 中 的 NIO.2 的 File 工具类的newByteChannel()
     25  * 
     26  * 四、通道之间的数据传输
     27  * transferForm()
     28  * transferTo()
     29  * 
     30  * 五、分散(Scatter) 与 聚集(Gather)
     31  * 分散读取(Scattering Reads):将通道中的数据分散到多个缓冲区
     32  * 聚集写入(Gathering Writes):将多个缓冲区中的 数据 聚集到通道中
     33  * 
     34  * 六、字符集:Charset
     35  * 编码:字符串 -> 字节数组
     36  * 解码: 字节数组 -> 字符串
     37  * 
     38  * */
     39 public class TestChannel {
     40     
     41     //使用指定字符集 进行编码 和 解码
     42     @Test
     43     public void test6() throws IOException {
     44         //1.选择字符集
     45         Charset charset1 = Charset.forName("GBK");
     46         
     47         //2.获取编码器
     48         CharsetEncoder encoder = charset1.newEncoder();
     49         
     50         //3.获取解码器
     51         CharsetDecoder decoder = charset1.newDecoder();
     52         
     53         //4.创建字符串缓冲区,放入需要编码的字符串
     54         CharBuffer charBuffer = CharBuffer.allocate(1024);
     55         charBuffer.put("迅雷影音");
     56         
     57         //5.对字符串进行编码  (编码:字符串 -> 字节数组)
     58         charBuffer.flip();    //操作字符串缓冲区,解码字符串之前 需要 flip 一下
     59         ByteBuffer byteBuffer = encoder.encode(charBuffer);
     60 
     61         // byteBuffer 此时 是 初始状态,即position 是0
     62         //调用 这个 for ,每 get 一次,position + 1 
     63         //这样才能 在 flip 之后, 解码 需要操作的数据
     64         for(int i = 0;i<8;i++) {
     65             System.out.println(byteBuffer.position());
     66             System.out.println(byteBuffer.get());
     67         }
     68         
     69         //6.对字节数组进行解码 (解码: 字节数组 -> 字符串)
     70         byteBuffer.flip();    //操作字节缓冲区,解码字节数组之前 需要 flip 一下
     71         CharBuffer charBuffer2 = decoder.decode(byteBuffer);
     72         
     73         //打印解码后的数据
     74         System.out.println(charBuffer2.toString());
     75     }
     76     
     77     //5.显示所有的字符集
     78     @Test
     79     public void test5() {
     80         Map<String,Charset> map = Charset.availableCharsets();
     81         Set<Entry<String, Charset>> set = map.entrySet();
     82         
     83         for(Entry<String, Charset> entry:set) {
     84             System.out.println(entry.getKey() + " = " + entry.getValue());
     85         }
     86     }
     87 
     88     //4.分散和 聚集 (多个缓冲区)
     89     @Test
     90     public void test4() throws IOException {
     91         // "rw" 是指 具有read 和 write 的 权限
     92         RandomAccessFile raf = new RandomAccessFile("1.txt", "rw");
     93         //1.获取通道
     94         FileChannel channel1 = raf.getChannel();
     95         
     96         //2.分配指定大小的缓冲区 (多个)
     97         ByteBuffer buf1 = ByteBuffer.allocate(100);
     98         ByteBuffer buf2 = ByteBuffer.allocate(1024);
     99         ByteBuffer[] bufs = {buf1,buf2};
    100         
    101         
    102         //4.聚集写入
    103         RandomAccessFile raf2 = new RandomAccessFile("2.txt","rw");
    104         FileChannel channel2 = raf2.getChannel();
    105         
    106         
    107         //3.分散读取    
    108         while(channel1.read(bufs)!= -1) {
    109             for(ByteBuffer buf:bufs) {
    110                 buf.flip();
    111             }
    112             //4.聚集写入
    113             channel2.write(bufs);
    114             
    115             System.out.println("-----------------缓冲区1---------------");
    116             System.out.println(new String(bufs[0].array(),0,bufs[0].limit()) );
    117             System.out.println("-----------------缓冲区1---------------");
    118             
    119             System.out.println("-----------------缓冲区2---------------");
    120             System.out.println(new String(bufs[1].array(),0,bufs[1].limit()));
    121             System.out.println("-----------------缓冲区2---------------");
    122             
    123             for(ByteBuffer buf:bufs) {
    124                 buf.clear();
    125             }
    126         
    127 
    128         }            
    129         
    130     }
    131     
    132     //3.通道之间的数据传输
    133     @Test
    134     public void test3() throws Exception {
    135         FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
    136         FileChannel outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);
    137         
    138         //直接使用transferTo 或者 transferFrom 完成通道之间的数据传输
    139         inChannel.transferTo(0, inChannel.size(), outChannel);
    140         outChannel.transferFrom(inChannel, 0, inChannel.size());
    141         
    142         inChannel.close();
    143         outChannel.close();
    144     }
    145     
    146     //2.使用直接缓冲区完成文件的复制(内存映射文件)(这种方式效率更高)
    147     //会出现的问题 :文件传输已经完成,但是程序仍然没有结束,因为 java 虚拟机无法及时 对 内存映射文件进行  进行释放,必须要等指向映射文件的那个变量被回收
    148     @Test
    149     public void test2() {
    150         
    151         long start = System.currentTimeMillis();
    152         
    153         FileChannel inChannel = null;
    154         FileChannel outChannel = null;
    155         MappedByteBuffer inMapperBuf = null;
    156         MappedByteBuffer outMapperBuf = null;
    157         
    158         try {
    159             //使用 FileChannel 的 open方法 (可以不用创建流就可以得到通道)
    160             inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
    161             outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);
    162         
    163             //内存映射文件 (也是一个 缓冲区 ,继承自 ByteBuffer,直接缓冲区也只能使用 ByteBuffer)
    164             inMapperBuf = inChannel.map(MapMode.READ_ONLY,0 , inChannel.size());
    165             outMapperBuf = outChannel.map(MapMode.READ_WRITE,0 , inChannel.size());
    166             
    167         } catch (IOException e) {
    168             e.printStackTrace();
    169         }  
    170 
    171     
    172         //直接对缓冲区进行数据读写操作
    173         byte[] bytes = new byte[inMapperBuf.limit()];
    174         inMapperBuf.get(bytes);
    175         outMapperBuf.put(bytes);
    176         
    177         try {
    178             if(inChannel != null) {
    179                 inChannel.close();
    180             }
    181             if(outChannel != null) {
    182                 outChannel.close();
    183             }
    184         } catch (IOException e) {
    185             e.printStackTrace();
    186         }
    187         
    188         long end = System.currentTimeMillis();
    189         System.out.println("花费:" +  (end-start));
    190         
    191     }
    192     
    193     //1.利用通道完成文件的复制
    194     @Test
    195     public void test1() {
    196         long start = System.currentTimeMillis();
    197         
    198         FileInputStream fis = null;
    199         FileOutputStream fos = null;
    200         try {
    201             fis = new FileInputStream("1.jpg");
    202             fos = new FileOutputStream("2.jpg");
    203         } catch (FileNotFoundException e) {
    204             e.printStackTrace();
    205         }
    206         
    207         //1.获取流对应的 通道
    208         FileChannel inChannel = fis.getChannel();
    209         FileChannel outChannel = fos.getChannel();
    210         
    211         //2.分配指定大小的缓冲区
    212         ByteBuffer buffer = ByteBuffer.allocate(1024);
    213         
    214         //3.将通道中的数据存入缓存区
    215         try {
    216             //read 方法,从Channel 中读取数据到 ByteBuffer (即往 缓冲区中 put 数据),所以不用 flip
    217             while(inChannel.read(buffer) != -1) {
    218                 buffer.flip();  //切换到读取数据模式            
    219                 
    220                 //4.将缓存区中的数据写入通道中 (需要get 出 缓冲区中的 数据 ,所以需要 flip)
    221                 outChannel.write(buffer);
    222                 buffer.clear();  //清空缓冲区,使其继续循环
    223             }
    224         } catch (IOException e) {
    225             e.printStackTrace();
    226         } finally {
    227             if(inChannel != null) {
    228                 try {
    229                     inChannel.close();
    230                 } catch (IOException e) {                
    231                     e.printStackTrace();
    232                 }
    233             }
    234             if(outChannel != null) {
    235                 try {
    236                     outChannel.close();
    237                 } catch (IOException e) {                    
    238                     e.printStackTrace();
    239                 }
    240             }
    241             if(fis != null) {
    242                 try {
    243                     fis.close();
    244                 } catch (IOException e) {                    
    245                     e.printStackTrace();
    246                 }
    247             }
    248             if(fos != null) {
    249                 try {
    250                     fos.close();
    251                 } catch (IOException e) {                    
    252                     e.printStackTrace();
    253                 }
    254             }    
    255         }
    256         
    257         long end = System.currentTimeMillis();
    258         System.out.println("花费:" +  (end-start));        
    259     }
    260     
    261 }


      

  • 相关阅读:
    vim does not map customized key?
    再说vundle: 完全vim字符编程的四个必须插件
    centos7 没有iptables服务 file or directory? 用secureCRT登录centos?
    php基础语法-函数等
    windows下vmware10.0 安装centos7
    fedora23的firefox不能播放优酷视频?
    linux如何隐藏和显示所有窗口?
    fedora23忘记root密码怎么办??
    mouse scrollings and zooming operations in linux & windows are opposite
    windows 杂项
  • 原文地址:https://www.cnblogs.com/xuzekun/p/7435504.html
Copyright © 2011-2022 走看看