zoukankan      html  css  js  c++  java
  • NIO基本操作

    NIO是Java 4里面提供的新的API,目的是用来解决传统IO的问题

    NIO主要有三大核心部分:Channel(通道),Buffer(缓冲区), Selector(选择器)

    Channel(通道)

    通道:类似于流,但是可以异步读写数据(流只能同步读写),通道是双向的,(流是单向的),通道的数据总是要先读到一个buffer 或者 从一个buffer写入,即通道与buffer进行数据交互。

      通道类型:  

    FileChannel:从文件中读写数据。  

    DatagramChannel:能通过UDP读写网络中的数据。  

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

    ServerSocketChannel:可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。 

      通过使用FileChannel可以从文件读或者向文件写入数据;通过SocketChannel,以TCP来向网络连接的两端读写数据;通过ServerSocketChanel能够监听客户端发起的TCP连接,并为每个TCP连接创建一个新的SocketChannel来进行数据读写;通过DatagramChannel,以UDP协议来向网络连接的两端读写数据。

    Buffer(缓冲区)

    缓冲区 本质上是一块可以存储数据的内存,被封装成了buffer对象而已!

    缓冲区类型:

    ByteBuffer

    MappedByteBuffer

    CharBuffer  

    DoubleBuffer  

    FloatBuffer  

    IntBuffer  

    LongBuffer  

    ShortBuffer 

    常用方法:

    allocate() - 分配一块缓冲区  

    put() -  向缓冲区写数据

    get() - 向缓冲区读数据  

    filp() - 将缓冲区从写模式切换到读模式  

    clear() - 从读模式切换到写模式,不会清空数据,但后续写数据会覆盖原来的数据,即使有部分数据没有读,也会被遗忘;  

    compact() - 从读数据切换到写模式,数据不会被清空,会将所有未读的数据copy到缓冲区头部,后续写数据不会覆盖,而是在这些数据之后写数据

    mark() - 对position做出标记,配合reset使用

    reset() - 将position置为标记值 

    hasRemaining() - 判断是否还有可用数据

    缓冲区的一些属性:

    capacity - 缓冲区大小,无论是读模式还是写模式,此属性值不会变;

    position - 写数据时,position表示当前写的位置,每写一个数据,会向下移动一个数据单元,初始为0;最大为capacity - 1切换到读模式时,position会被置为0,表示当前读的位置

    limit - 写模式下,limit 相当于capacity 表示最多可以写多少数据,切换到读模式时,limit 等于原先的position,表示最多可以读多少数据。

    Selector(选择器)

    选择器:相当于一个观察者,用来监听通道感兴趣的事件,一个选择器可以绑定多个通道;

    通道向选择器注册时,需要指定感兴趣的事件,选择器支持以下事件:

    SelectionKey.OP_CONNECT

    SelectionKey.OP_ACCEPT

    SelectionKey.OP_READ

    SelectionKey.OP_WRITE  

     如果你对不止一种事件感兴趣,那么可以用“位或”操作符将常量连接起来,如下:

         int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE; 

     通道向选择器注册时,会返回一个 SelectionKey对象,具有如下属性

    interest集合

    ready集合  

    Channel  

    Selector

    附加的对象(可选) 

    用“位与”操作interest 集合和给定的SelectionKey常量,可以确定某个确定的事件是否在interest 集合中。

    int interestSet = selectionKey.interestOps();  
     
    boolean isInterestedInAccept  = interestSet & SelectionKey.OP_ACCEPT;
    boolean isInterestedInConnect = interestSet & SelectionKey.OP_CONNECT; boolean isInterestedInRead = interestSet & SelectionKey.OP_READ; boolean isInterestedInWrite = interestSet & SelectionKey.OP_WRITE;

    ready 集合是通道已经准备就绪的操作的集合。在一次选择(Selection)之后,你会首先访问这个ready set。Selection将在下一小节进行解释。可以这样访问ready集合: 
      int readySet = selectionKey.readyOps();

    也可以使用以下四个方法获取已就绪事件,返回值为boolean:

    selectionKey.isAcceptable();  
    selectionKey.isConnectable();  
    selectionKey.isReadable();  
    selectionKey.isWritable();  

    可以将一个对象或者更多信息附着到SelectionKey上,即记录在附加对象上,方法如下:

    selectionKey.attach(theObject);  
    Object attachedObj = selectionKey.attachment();  

    可以通过选择器的select方法获取是否有就绪的通道;

    int select()  

    int select(long timeout)  

    int selectNow()

    返回值表示上次执行select之后,就绪通道的个数。 

    可以通过selectedKeySet获取已就绪的通道。返回值是SelectionKey 的集合,处理完相应的通道之后,需要removed 因为Selector不会自己removed

    select阻塞后,可以用wakeup唤醒;执行wakeup时,如果没有阻塞的select  那么执行完wakeup后下一个执行select就会立即返回。

    调用close() 方法关闭selector

    传统IO和NIO简单例子

    传统IO读取文件:

    public static void ioRead() {
            File file = new File("f:/io.txt");
            InputStream in = null;
            try {
                in = new FileInputStream(file);
                byte[] bytes = new byte[1024];
                in.read(bytes);
                System.out.println(new String(bytes));
    
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    NIO操作

    public static void nioRead() {
            RandomAccessFile aFile = null;
            try {
                aFile = new RandomAccessFile("F:/io.txt", "rw");
                FileChannel fileChannel = aFile.getChannel();
                ByteBuffer buf = ByteBuffer.allocate(1024);
                int bytesRead = fileChannel.read(buf);
                System.out.println(bytesRead);
                while (bytesRead != -1) {
                    buf.flip();
                    while (buf.hasRemaining()) {
                        System.out.print((char) buf.get());
                    }
                    buf.compact();
                    bytesRead = fileChannel.read(buf);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (aFile != null) {
                        aFile.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
  • 相关阅读:
    BZOJ.4293.[PA2015]Siano(线段树)
    洛谷.T21778.过年(线段树 扫描线)
    HDU.6155.Subsequence Count(线段树 矩阵)
    BZOJ.3687.简单题(bitset)
    var let const的区别
    2、electron进程
    1、Electron入门HelloWorld案例
    JUnit@Before失效
    十一、Thymeleaf的基础使用
    九、SpringBoot集成Thymeleaf模板引擎
  • 原文地址:https://www.cnblogs.com/grasp/p/10018035.html
Copyright © 2011-2022 走看看