NIO 概述:

1. Java NIO 由以下几个核心部分组成:Channels       Buffers           Selectors

2. 主要Channel的实现:FileChannel          DatagramChannel               SocketChannel          ServerSocketChannel

3. 关键的Buffer实现:ByteBuffer        CharBuffer           DoubleBuffer       FloatBuffer       IntBuffer        LongBuffer         ShortBuffer

4. Selector允许单线程处理多个 Channel。如果你的应用打开了多个连接(通道),但每个连接的流量都很低,使用Selector就会很方便

channel:

1. Java NIO的通道类似流,但又有些不同:既可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的。通道可以异步地读写。通道中的数据总是要先读到一个Buffer,

或者总是要从一个Buffer中写入

2. FileChannel 从文件中读写数据。

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

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

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

Buffer:

1. Java NIO中的Buffer用于和NIO通道进行交互。如你所知,数据是从通道读入缓冲区,从缓冲区写入到通道中的。

2. 使用Buffer读写数据一般遵循以下四个步骤:

    1).写入数据到Buffer

    2).调用flip()方法

    3).从Buffer中读取数据

    4).调用clear()方法或者compact()方法

3. 当向buffer写入数据时,buffer会记录下写了多少数据。一旦要读取数据,需要通过flip()方法将Buffer从写模式切换到读模式。在读模式下,可以读取之前写入到buffer的所有数据。

    一旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入。有两种方式能清空缓冲区:调用clear()或compact()方法。clear()方法会清空整个缓冲区。compact()方法只会清除

    已经读过的数据。任何未读的数据都被移到缓冲区的起始处,新写入的数据将放到缓冲区未读数据的后面。

    如果不调用flip()方法直接读取,会从当前position开始读取。调用完flip()方法后,会从0开始读取。position位置后面的内容不会读取。

4. 三个属性:

capacity : 作为一个内存块,Buffer有一个固定的大小值,也叫“capacity”.

position : 当你写数据到Buffer中时,position表示当前的位置。初始的position值为0.当一个byte、long等数据写到Buffer后, position会向前移动到下一个可插入数据的Buffer单元。

position最大可为capacity – 1.当读取数据时,也是从某个特定位置读。当将Buffer从写模式切换到读模式,position会被重置为0. 当从Buffer的position处读取数据时,

position向前移动到下一个可读的位置。

limit : 在写模式下,Buffer的limit表示你最多能往Buffer里写多少数据。 写模式下,limit等于Buffer的capacity。当切换Buffer到读模式时, limit表示你最多能读到多少数据。

position和limit的含义取决于Buffer处在读模式还是写模式。不管Buffer处在什么模式,capacity的含义总是一样的。

5. Buffer的分配 : allocate , ByteBuffer buf = ByteBuffer.allocate(48);

6. 向Buffer中写数据,两种方式:

从Channel写到Buffer的例子:int bytesRead = inChannel.read(buf);       //read into buffer.

通过put方法写Buffer的例子:buf.put(127);            put方法有很多版本,允许你以不同的方式把数据写入到Buffer中

7. flip()方法:flip方法将Buffer从写模式切换到读模式。调用flip()方法会将position设回0,并将limit设置成之前position的值。

8. 从Buffer中读取数据:

从Buffer读取数据到Channel的例子:int bytesWritten = inChannel.write(buf);

使用get()方法从Buffer中读取数据的例子:byte aByte = buf.get(); get方法有很多版本,允许你以不同的方式从Buffer中读取数据。

9. rewind()方法:Buffer.rewind()将position设回0,所以你可以重读Buffer中的所有数据。limit保持不变,仍然表示能从Buffer中读取多少个元素(byte、char等)。

10. clear()与compact()方法:让Buffer准备好再次被写入。可以通过clear()或compact()方法来完成。

如果调用的是clear()方法,position将被设回0,limit被设置成 capacity的值。换句话说,Buffer 被清空了。Buffer中的数据并未清除,只是这些标记告诉我们可以从哪里开始往

Buffer里写数据。如果Buffer中有一些未读的数据,调用clear()方法,数据将“被遗忘”,意味着不再有任何标记会告诉你哪些数据被读过,哪些还没有。

如果Buffer中仍有未读的数据,且后续还需要这些数据,但是此时想要先先写些数据,那么使用compact()方法。

compact()方法将所有未读的数据拷贝到Buffer起始处。然后将position设到最后一个未读元素正后面。limit属性依然像clear()方法一样,设置成capacity。现在Buffer准备好写数据了,

但是不会覆盖未读的数据。

11. mark()与reset()方法:通过调用Buffer.mark()方法,可以标记Buffer中的一个特定position。之后可以通过调用Buffer.reset()方法恢复到这个position。

12. equals只是比较Buffer的一部分,不是每一个在它里面的元素都比较。实际上,它只比较Buffer中的剩余元素。

有相同的类型(byte、char、int等)。Buffer中剩余的byte、char等的个数相等。Buffer中所有剩余的byte、char等都相同。

13. compareTo()方法:compareTo()方法比较两个Buffer的剩余元素(byte、char等), 如果满足下列条件,则认为一个Buffer“小于”另一个Buffer:

第一个不相等的元素小于另一个Buffer中对应的元素 。所有元素都相等,但第一个Buffer比另一个先耗尽(第一个Buffer的元素个数比另一个少)。

Scatter/Gather

1. scatter / gather经常用于需要将传输的数据分开处理的场合,例如传输一个由消息头和消息体组成的消息,你可能会将消息体和消息头分散到不同的buffer中,这样你可以方便的处理

消息头和消息体

2. 分散(scatter)从Channel中读取是指在读操作时将读取的数据写入多个buffer中。因此,Channel将从Channel中读取的数据“分散(scatter)”到多个Buffer中。

实例代码如下:

ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body = ByteBuffer.allocate(1024);
ByteBuffer[] bufferArray = { header, body };
channel.read(bufferArray);

注意buffer首先被插入到数组,然后再将数组作为channel.read() 的输入参数。read()方法按照buffer在数组中的顺序将从channel中读取的数据写入到buffer,当一个buffer被写满后,

channel紧接着向另一个buffer中写。

3. 聚集(gather)写入Channel是指在写操作时将多个buffer的数据写入同一个Channel,因此,Channel 将多个Buffer中的数据“聚集(gather)”后发送到Channel。

实例代码:

ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body = ByteBuffer.allocate(1024);
ByteBuffer[] bufferArray = { header, body }; //write data into buffers
channel.write(bufferArray);

buffers数组是write()方法的入参,write()方法会按照buffer在数组中的顺序,将数据写入到channel,注意只有position和limit之间的数据才会被写入。因此,如果一个buffer的容量

为128byte,但是仅仅包含58byte的数据,那么这58byte的数据将被写入到channel中。因此与Scattering Reads相反,Gathering Writes能较好的处理动态消息。

通道之间的数据传输

1. 在Java NIO中,如果两个通道中有一个是FileChannel,那你可以直接将数据从一个channel传输到另外一个channel。

2. transferFrom()

FileChannel的transferFrom()方法可以将数据从源通道传输到FileChannel中。下面是一个简单的例子:

    RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw");

    FileChannel fromChannel = fromFile.getChannel();

    RandomAccessFile toFile = new RandomAccessFile("toFile.txt", "rw");

    FileChannel toChannel = toFile.getChannel();

    long position = 0;

    long count = fromChannel.size();

    toChannel.transferFrom(position, count, fromChannel);

方法的输入参数position表示从position处开始向目标文件写入数据,count表示最多传输的字节数。如果源通道的剩余空间小于 count 个字节,则所传输的字节数要小于请求的字节数。

此外要注意,在SoketChannel的实现中,SocketChannel只会传输此刻准备好的数据(可能不足count字节)。因此,SocketChannel可能不会将请求的所有数据(count个字节)全部传输

到FileChannel中。

3. transferTo()

transferTo()方法将数据从FileChannel传输到其他的channel中。下面是一个简单的例子:

    RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw");

    FileChannel fromChannel = fromFile.getChannel();

    RandomAccessFile toFile = new RandomAccessFile("toFile.txt", "rw");

    FileChannel toChannel = toFile.getChannel();

    long position = 0;

    long count = fromChannel.size();

    fromChannel.transferTo(position, count, toChannel);

上面所说的关于SocketChannel的问题在transferTo()方法中同样存在。SocketChannel会一直传输数据直到目标buffer被填满。

NIO复习01的更多相关文章

  1. Bone Collector(复习01背包)

    传送门 题目大意:01背包裸题. 复习01背包: 题目 有N件物品和一个容量为V的背包.第i件物品的费用是c[i],价值是w[i].求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总 ...

  2. JAVA NIO复习笔记

    1. JAVA NIO是什么? 从JDK1.4开始,java提供了一系列改进的输入/输出处理的新功能,这些功能被统称为新IO(New IO,简称NIO),新增了许多用于处理输入/输出的类,这些类都被放 ...

  3. NIO复习03

    SocketChannel: 1. Java NIO中的SocketChannel是一个连接到TCP网络套接字的通道.可以通过以下2种方式创建SocketChannel: 打开一个SocketChan ...

  4. NIO复习02

    Selector 1. Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件.这样,一个单独的线程可以管理多个channel,从而管 ...

  5. codevs 2837 考前复习——01背包

     时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解  查看运行结果     题目描述 Description Aiden马上要考试了,可他还没怎么复习,于是他 ...

  6. mybatis复习01

    1.mybatis的历史: mybatis是apache的一个开源项目,2010被google收购,转移到google code. mybatis是一个优秀的持久层框架,对jdbc操作进行了封装,是操 ...

  7. NIO入门-----01

    package com.sico.pck01_nio; import java.nio.ByteBuffer; import org.junit.Test; /**  * @author Sico   ...

  8. nodejs复习01

    console 格式化 console.log("%s:%s", "a", "b") //字符串 console.log("%d. ...

  9. C#基础总复习01

    马上就快毕业了,准备把这几个月所学到的知识梳理一下,这儿所写的都是一些C#中最基础的东西(大牛不要笑话我,这也是我记录的一些笔记等等),希望能帮到一些正在学习这方面的知识的人,如果有写的不对的地方,望 ...

随机推荐

  1. 【Cloud Foundry】Cloud Foundry学习(四)——Service

    在阅读的过程中有不论什么问题,欢迎一起交流 邮箱:1494713801@qq.com    QQ:1494713801 Services:Cloud Foundry的Service模块从源码控制上看就 ...

  2. [LAMP]安装-Debian

    sudo apt-get install build-essential sudo apt-get install mysql-server sudo apt-get install apache2 ...

  3. Java逍遥游记读书笔记<一>

    前言 必须先来一句,这是入门级别,高手勿喷~ 写Android的时候总有一些语句不是很理解,其实大部分是Java的内容,所以想系统的学下Java. 这本书——<Java逍遥游记>是在图书馆 ...

  4. 用原生JS模仿jquery,需要HTML5的支持

    jQuery是现在最流行的JavaScript工具库. 据统计,目前全世界57.3%的网站使用它.也就是说,10个网站里面,有6个使用jQuery.如果只考察使用工具库的网站,这个比例就会上升到惊人的 ...

  5. JavaScript------获取表单信息

    <form name="fname"> <input type="text" name="user" /> < ...

  6. 《ASP.NET 1200例》ref关键字与out关键字

    REF关键字 ref 关键字会导致通过引用传递的参数,而不是值. 通过引用传递的效果是在方法中对参数的任何改变都会反映在调用方的基础参数中. 引用参数的值与基础参数变量的值始终是一样的. 不要将“通过 ...

  7. Oracle数据库 number 长度与 Short Integer Long BigDecimal 对应关系

    转自:https://blog.csdn.net/edward9145/article/details/21398657 Oracle数据库 number 长度与 Short Integer Long ...

  8. Less-mixin函数基础一

    //mixin函数 立即执行mixin函数,example: .test{ color:#ff00000; background:red; } //立即执行mixin grammar 1 扩展exte ...

  9. Spoken English Practice(not always estimating your status in other's hearts. you will lose yourself when you live in other's look. do your best and walk on you own way.)

    绿色:连读:                  红色:略读:               蓝色:浊化:               橙色:弱读     下划线_为浊化 口语蜕变(2017/7/8) 英 ...

  10. 安装 oracle 11g 发行版 出现错误:由于以下错误,Enterprise Manager配置失败,启动Database Control时出错

    解决方案如下进入dos(1)查看dbconsole状态:emctl status dbconsole 显示:Environment variable ORACLE_SID not defined. P ...