zoukankan      html  css  js  c++  java
  • NIO Channel的学习笔记总结

    摘自:http://blog.csdn.net/tsyj810883979/article/details/6876603

    1.1  非阻塞模式

            Java  NIO非堵塞应用通常适用用在I/O读写等方面,我们知道,系统运行的性能瓶颈通常在I/O读写,包括对端口和文件的操作上,过去,在打开一个I/O通道后,read()将一直等待在端口一边读取字节内容,如果没有内容进来,read()也是傻傻的等,这会影响我们程序继续做其他事情,那么改进做法就是开设线程,让线程去等待,但是这样做也是相当耗费资源(传统socket通讯服务器设计模式)的。

      Java NIO非堵塞技术实际是采取Reactor模式,或者说是Observer模式为我们监察I/O端口,如果有内容进来,会自动通知我们,这样,我们就不必开启多个线程死等,从外界看,实现了流畅的I/O读写,不堵塞了。

      Java NIO出现不只是一个技术性能的提高,你会发现网络上到处在介绍它,因为它具有里程碑意义,从JDK1.4开始,Java开始提高性能相关的功能,从而使得Java在底层或者并行分布式计算等操作上已经可以和C或Perl等语言并驾齐驱。

      如果你至今还是在怀疑Java的性能,说明你的思想和观念已经完全落伍了,Java一两年就应该用新的名词来定义。从JDK1.5开始又要提供关于线程、并发等新性能的支持,Java应用在游戏等适时领域方面的机会已经成熟,Java在稳定自己中间件地位后,开始蚕食传统C的领域。

           NIO 有一个主要的Selector,这个类似一个观察者,只要我们把需要探知的socketchannel告诉Selector,我们接着做别的事情,当有事件发生时,他会通知我们,传回一组  SelectionKey,我们读取这些Key,就会获得我们刚刚注册过的socketchannel,然后,我们从这个Channel中读取数据,放心,包准能够读到,接着我们可以处理这些数据。  Selector内部原理实际是在做一个对所注册的channel的轮询访问,不断的轮询(目前就这一个算法),一旦轮询到一个channel有所注册的事情发生,比如数据来了,他就会站起来报告,交出一把钥匙,让我们通过这把钥匙(SelectionKey表示SelectableChannel在Selector中的注册的标记)来读取这个channel的内容。

    实现一:使用nio实现文件复制

    1. package study.nio;  
    2. import java.io.File;  
    3. import java.io.FileInputStream;  
    4. import java.io.FileOutputStream;  
    5. import java.io.FileNotFoundException;  
    6. import java.io.IOException;  
    7. import java.nio.channels.FileChannel;  
    8. import java.nio.ByteBuffer;  
    9. public class TestCopyFile {  
    10.     public static void main(String[] args) throws IOException {  
    11.         //调用FileManager类的copyFile静态方法  
    12.         FileManager.copyFile(new File("src.txt"), new File("dst.txt"));  
    13.     }  
    14. }  
    15. class FileManager {  
    16.     //把可能出现的异常抛给上层调用者处理  
    17.     public static void copyFile(File src, File dst)   
    18.             throws FileNotFoundException, IOException {  
    19.         //得到一个源文件对应的输入通道  
    20.         FileChannel fcin = new FileInputStream(src).getChannel();  
    21.         //得到一个目标文件对应的输出通道  
    22.         FileChannel fcout = new FileOutputStream(dst).getChannel();  
    23.         //生成一个1024字节的ByteBuffer实例  
    24.         ByteBuffer buf = ByteBuffer.allocate(1024);  
    25.         while(fcin.read(buf) != -1) {  
    26.             buf.flip();     //准备写  
    27.             fcout.write(buf);  
    28.             buf.clear();        //准备读  
    29.         }  
    30.     }  
    31.       
    32. }  

    还可以使用下面方式进行操作,在FileChannel中有两个特殊方法可以允许我们直接将两个通道相连:

    long transferFrom(ReadableByteChannel src, long position, long count);

    long transferTo(long position, long count, WriteableByteChannel targets);

    上面while循环可以替换为:

    fcin.transferTo(0, fcin.size(), fcout); 或者 fcout.transferFrom(fcin, 0, fcin.size());

    实现二:向一个空文件中写入some text,再以只读方式打开该文件,在尾部追加some more,最终将该文件内容输出。

    1. package study.nio;  
    2. import java.io.File;  
    3. import java.io.FileInputStream;  
    4. import java.io.FileOutputStream;  
    5. import java.io.RandomAccessFile;  
    6. import java.nio.ByteBuffer;  
    7. import java.nio.channels.FileChannel;  
    8.   
    9. public class GetChannel {  
    10.     //为了使代码明晰,暂不处理异常  
    11.     public static void main(String[] args) throws Exception {  
    12.         FileChannel fc = null;  
    13.         //向一个文件中写入文本  
    14.         fc = new FileOutputStream(new File("data.txt")).getChannel();  
    15.         fc.write(ByteBuffer.wrap("some text".getBytes()));  
    16.         fc.close();  
    17.         //以读写方式打开文件,并在尾部追加内容  
    18.         fc = new RandomAccessFile("data.txt", "rw").getChannel();  
    19.         fc.position(fc.size());  
    20.         fc.write(ByteBuffer.wrap("some more".getBytes()));  
    21.         fc.close();  
    22.         //将文件里的内容读出来  
    23.         fc = new FileInputStream("data.txt").getChannel();  
    24.         ByteBuffer buf = ByteBuffer.allocate(1024);  
    25.         fc.read(buf);  
    26.         buf.flip();  
    27.         while(buf.hasRemaining()) {  
    28.             System.out.print((char)buf.get());  
    29.         }         
    30.     }  
    31. }  

    以上均使用的是字节操作流,与nio相一致。Reader和Writer这些字符模式类不能用于产生通道,但是java.nio.channels.Channels类中提供了实用方法,可以在通道中产生Reader和Writer。  Channels.newReader();  Channels.newWriter();

    实现三:将一个大文件映射到内存并查找指定的文本内容是否在该文件中(曾记得李开复与微软的故事,当然李开复是从邮件中查找信息,并且邮件被截成了图片,⊙﹏⊙b汗)

    1. public class LargeMappedFiles {  
    2.     public static void main(String args[]) {     
    3.         try {  
    4.             File[] files = new File[] {new File("src1.txt"), new File("src2.txt")};   
    5.           ArrayList<String> ls = search(files, "something is wrong");  
    6.           for(int i=0; i<ls.size(); i++) {  
    7.             System.out.println(ls.get(i));  
    8.           }  
    9.         } catch (FileNotFoundException e) {     
    10.             e.printStackTrace();     
    11.         } catch (Exception e) {     
    12.             e.printStackTrace();     
    13.         }     
    14.     }  
    15.     //实现简单的内容检索  
    16.     private static ArrayList<String> search(File[] files, String text) throws Exception {  
    17.         //把检索结果放到一个list中  
    18.         ArrayList<String> result = new ArrayList<String>();  
    19.         //循环遍历文件  
    20.         for(File src : files) {  
    21.             //将整个文件映射到内存  
    22.             MappedByteBuffer dst = new RandomAccessFile(src, "rw")  
    23.             .getChannel()     
    24.             .map(FileChannel.MapMode.READ_WRITE, 0, src.length());  
    25.         //对字符进行解码  
    26.         String str = Charset.forName("UTF-8").decode(dst).toString();  
    27.         //准备进行读  
    28.         dst.flip();  
    29.         if(str.indexOf(text) != -1) {  
    30.             result.add(src.getName());  
    31.         }  
    32.         //准备写  
    33.         dst.clear();  
    34.         }  
    35.         return result;  
    36.     }  
    37. }  

    实现四:在前面的学习中了解到nio为所有原始数据类型提供了Buffer支持,并且在ByteBuffer中实现了asXBuffer()方法直接将一个ByteBuffer转换成其它类型的Buffer。本例实现数据类型的转换。

    1. import java.nio.IntBuffer;  
    2. import java.nio.FloatBuffer;  
    3. import java.nio.ByteBuffer;  
    4. import java.util.Arrays;  
    5.   
    6. public class CastBuffer {  
    7.     static byte[] bytes = new byte[] {0, 1, 2, 3, 4, 5, 'a', 'b', 'c'};  
    8.           
    9.     public static void main(String[] args) {  
    10.         ByteBuffer bBuf = ByteBuffer.wrap(bytes);  
    11.         System.out.println(Arrays.toString(bBuf.array()));  
    12.         //转换成IntBuffer  
    13.         IntBuffer iBuf = ((ByteBuffer)bBuf.rewind()).asIntBuffer();  
    14.         while(iBuf.hasRemaining()) {  
    15.             System.out.print(iBuf.get()+",");  
    16.         }  
    17.         //转换成FloatBuffer  
    18.         FloatBuffer fBuf = ((ByteBuffer)bBuf.rewind()).asFloatBuffer();  
    19.         while(fBuf.hasRemaining()) {  
    20.             System.out.print(fBuf.get()+",");  
    21.         }  
    22.     }  
    23. }  

    其它类型转换与上面方法类似,各种方法都相似。

     

  • 相关阅读:
    logging- 日志记录
    apscheduler -定时任务
    mysql
    Time-python
    pandas 常用语句
    re 正则
    sublime text3的快捷键
    git 常用操作
    tf.nn的conv2d卷积与max_pool池化
    WebApi 接口返回值类型详解 ( 转 )
  • 原文地址:https://www.cnblogs.com/whsa/p/4223859.html
Copyright © 2011-2022 走看看