NIO复习01
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的更多相关文章
- Bone Collector(复习01背包)
传送门 题目大意:01背包裸题. 复习01背包: 题目 有N件物品和一个容量为V的背包.第i件物品的费用是c[i],价值是w[i].求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总 ...
- JAVA NIO复习笔记
1. JAVA NIO是什么? 从JDK1.4开始,java提供了一系列改进的输入/输出处理的新功能,这些功能被统称为新IO(New IO,简称NIO),新增了许多用于处理输入/输出的类,这些类都被放 ...
- NIO复习03
SocketChannel: 1. Java NIO中的SocketChannel是一个连接到TCP网络套接字的通道.可以通过以下2种方式创建SocketChannel: 打开一个SocketChan ...
- NIO复习02
Selector 1. Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件.这样,一个单独的线程可以管理多个channel,从而管 ...
- codevs 2837 考前复习——01背包
时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 查看运行结果 题目描述 Description Aiden马上要考试了,可他还没怎么复习,于是他 ...
- mybatis复习01
1.mybatis的历史: mybatis是apache的一个开源项目,2010被google收购,转移到google code. mybatis是一个优秀的持久层框架,对jdbc操作进行了封装,是操 ...
- NIO入门-----01
package com.sico.pck01_nio; import java.nio.ByteBuffer; import org.junit.Test; /** * @author Sico ...
- nodejs复习01
console 格式化 console.log("%s:%s", "a", "b") //字符串 console.log("%d. ...
- C#基础总复习01
马上就快毕业了,准备把这几个月所学到的知识梳理一下,这儿所写的都是一些C#中最基础的东西(大牛不要笑话我,这也是我记录的一些笔记等等),希望能帮到一些正在学习这方面的知识的人,如果有写的不对的地方,望 ...
随机推荐
- ubuntu 终端$换行
编辑~/.bashrc文件 sudo gedit ~/.bashrc 红色部分为添加的 \n if [ "$color_prompt" = yes ]; then PS1= ...
- git上解决代码冲突(merge版)
1.切换到master: git checkout master 2.拉最新代码:git pull origin master 3.切换到提交的分支:git checkout Txxxx 4.合并:g ...
- unity 打开文件夹并鼠标选中某文件
System.Diagnostics.Process p = new System.Diagnostics.Process(); p.StartInfo.FileName = "explor ...
- 【ask】ghost分区还原win7出现蓝屏,试图加载CLASSPNP驱动时出现
1.最近由于需要把整个c盘备份了,然后还原在另一台机器上. 2.结果当然时出事了,开始一切如旧,但是机器重启后,蓝屏了. 3.哦,开始立马觉得可能时因为有些软件的驱动是装载d盘了. 4.赶紧把d盘也备 ...
- Android之怎样强制横竖屏显示
2 强制横屏竖屏显示(不依据手机传感器调整) 在清单文件AndroidManifest.xml中 在<activity 里面增加: android:screenOrientation=&quo ...
- GIT 回退出错 Unlink of file 'xx' failed. Should I try again? (y/n) 解决办法
发生过程 回退版本 如果回退版本时 里面有删除或者移动的文件 容易出这个问题 解决方法 git reset --hard 版本号 回退失败了 就 本地工作目录跟版本那个工作目录比较 然后还原修 ...
- IOS控件:长度单位换算(UITextField,IBAction,委托事件touchesBegan)
#import <UIKit/UIKit.h> @interface demo7_dayViewController : UIViewController { IBOutlet UITex ...
- 认识tornado(二)
前面我们对 Tornado 自带的 hello world 作了代码组织上的解释,但是没有更加深入细致地解释.这里我们直接从main()函数开始,单步跟随,看看tornado都干了些什么. 下面是 m ...
- Linux下自动调整时间和时区与Internet时间同步
(原文链接) 调整linux系统时间和时区与Internet时间同步一.修改时区:# cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime修改为中国的 ...
- 【BZOJ3166】[Heoi2013]Alo 可持久化Trie树+set
[BZOJ3166][Heoi2013]Alo Description Welcome to ALO ( Arithmetic and Logistic Online).这是一个VR MMORPG , ...