NIO理解
ByteBuffer Test:
package java_guide;
import java.nio.ByteBuffer;
public class ByteBufferMethods {
public static void main(String[] args) {
//分配缓冲区(Allocating a Buffer)
ByteBuffer buffer = ByteBuffer.allocate(33);
System.out.println("--------Test reset----------");
//clear()方法,position将被设回0,limit被设置成 capacity的值
buffer.clear();
// 设置这个缓冲区的位置
buffer.position(5);
//将此缓冲区的标记设置在其位置。没有 buffer.mark();这句话会报错
buffer.mark();
buffer.position(10);
System.out.println("before reset:" + buffer);
//将此缓冲区的位置重置为先前标记的位置。(buffer.position(5))
buffer.reset();
System.out.println("after reset:" + buffer);
System.out.println("--------Test rewind--------");
//position = 0;limit = capacity;mark = -1; 有点初始化的味道,但是并不影响底层byte数组的内容
buffer.clear();
buffer.position(10);
//返回此缓冲区的限制
buffer.limit(15);
System.out.println("before rewind:" + buffer);
//把position设为0,mark设为-1,不改变limit的值
buffer.rewind();
System.out.println("before rewind:" + buffer);
System.out.println("--------Test compact--------");
buffer.clear();
buffer.put("abcd".getBytes());
System.out.println("before compact:" + buffer);
System.out.println(new String(buffer.array()));
//翻转就是将一个处于存数据状态的缓冲区变为一个处于准备取数据的状态 limit变为之前的position
buffer.flip();
System.out.println("after flip:" + buffer);
//get()方法:相对读,从position位置读取一个byte,并将position+1,为下次读写作准备
System.out.println((char) buffer.get());
System.out.println((char) buffer.get());
System.out.println((char) buffer.get());
System.out.println("after three gets:" + buffer);
System.out.println("\t" + new String(buffer.array()));
//把从position到limit中的内容移到0到limit-position的区域内,position和limit的取值也分别变成limit-position、capacity。
// 如果先将positon设置到limit,再compact,那么相当于clear()
buffer.compact();
System.out.println("after compact:" + buffer);
System.out.println("\t" + new String(buffer.array()));
System.out.println("------Test get-------------");
buffer = ByteBuffer.allocate(32);
buffer.put((byte) 'a').put((byte) 'b').put((byte) 'c').put((byte) 'd').put((byte) 'e').put((byte) 'f');
System.out.println("before flip()" + buffer);
// 转换为读取模式
buffer.flip();
System.out.println("before get():" + buffer);
System.out.println((char) buffer.get());
System.out.println("after get():" + buffer);
// get(index)不影响position的值
System.out.println((char) buffer.get(2));
System.out.println("after get(index):" + buffer);
byte[] dst = new byte[10];
buffer.get(dst, 0, 2);
System.out.println("after get(dst, 0, 2):" + buffer);
System.out.println("\t dst:" + new String(dst));
System.out.println("buffer now is:" + buffer);
System.out.println("\t" + new String(buffer.array()));
System.out.println("--------Test put-------");
ByteBuffer bb = ByteBuffer.allocate(32);
System.out.println("before put(byte):" + bb);
System.out.println("after put(byte):" + bb.put((byte) 'z'));
System.out.println("\t" + bb.put(2, (byte) 'c'));
// put(2,(byte) 'c')不改变position的位置
System.out.println("after put(2,(byte) 'c'):" + bb);
System.out.println("\t" + new String(bb.array()));
// 这里的buffer是 abcdef[pos=3 lim=6 cap=32]
bb.put(buffer);
System.out.println("after put(buffer):" + bb);
System.out.println("\t" + new String(bb.array()));
}
}
输出:
--------Test reset----------
before reset:java.nio.HeapByteBuffer[pos=10 lim=33 cap=33]
after reset:java.nio.HeapByteBuffer[pos=5 lim=33 cap=33]
--------Test rewind--------
before rewind:java.nio.HeapByteBuffer[pos=10 lim=15 cap=33]
before rewind:java.nio.HeapByteBuffer[pos=0 lim=15 cap=33]
--------Test compact--------
before compact:java.nio.HeapByteBuffer[pos=4 lim=33 cap=33]
abcd
after flip:java.nio.HeapByteBuffer[pos=0 lim=4 cap=33]
a
b
c
after three gets:java.nio.HeapByteBuffer[pos=3 lim=4 cap=33]
abcd
after compact:java.nio.HeapByteBuffer[pos=1 lim=33 cap=33]
dbcd
------Test get-------------
before flip()java.nio.HeapByteBuffer[pos=6 lim=32 cap=32]
before get():java.nio.HeapByteBuffer[pos=0 lim=6 cap=32]
a
after get():java.nio.HeapByteBuffer[pos=1 lim=6 cap=32]
c
after get(index):java.nio.HeapByteBuffer[pos=1 lim=6 cap=32]
after get(dst, 0, 2):java.nio.HeapByteBuffer[pos=3 lim=6 cap=32]
dst:bc
buffer now is:java.nio.HeapByteBuffer[pos=3 lim=6 cap=32]
abcdef
--------Test put-------
before put(byte):java.nio.HeapByteBuffer[pos=0 lim=32 cap=32]
after put(byte):java.nio.HeapByteBuffer[pos=1 lim=32 cap=32]
java.nio.HeapByteBuffer[pos=1 lim=32 cap=32]
after put(2,(byte) 'c'):java.nio.HeapByteBuffer[pos=1 lim=32 cap=32]
z c
after put(buffer):java.nio.HeapByteBuffer[pos=4 lim=32 cap=32]
zdef
FileChannel Test:
package java_guide; import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel; public class FileChannelTest {
public static void main(String[] args) {
RandomAccessFile raf;
try {
raf = new RandomAccessFile("D:\\workspace\\jian_zhi_offer\\src\\resource\\test.txt", "rw");
FileChannel inChannel = raf.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buffer); ByteBuffer buffer2 = ByteBuffer.allocate(48);
buffer2.put("hello world\n".getBytes());
buffer2.flip();
inChannel.write(buffer2, 0);
while (bytesRead != -1) {
System.out.println("Reads:" + bytesRead);
buffer.flip();
while (buffer.hasRemaining()) {
System.out.print((char) buffer.get());
}
buffer.clear();
bytesRead = inChannel.read(buffer);
}
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Reads:48
hello world
ldvvv
ddddddddddddd
fffffffffffffReads:44
fhello world
eeeeeeeeeeeeeeeeeeee
54654465
通过上述实例代码,我们可以大概总结出FileChannel的一般使用规则:
1. 开启FileChannel
使用之前,FileChannel必须被打开 ,但是你无法直接打开FileChannel(FileChannel是抽象类)。需要通过 InputStream , OutputStream 或 RandomAccessFile 获取FileChannel。
2. 从FileChannel读取数据/写入数据
从FileChannel中读取数据/写入数据之前首先要创建一个Buffer(缓冲区)对象,
3. 关闭FileChannel
C/S架构的channel:
package java_guide; import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel; public class WebClient {
public static void main(String[] args) throws IOException {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("127.0.0.1", 3333));
ByteBuffer writeBuffer = ByteBuffer.allocate(128);
writeBuffer.put("hello this message is from client".getBytes());
writeBuffer.flip();
socketChannel.write(writeBuffer);
ByteBuffer readBuffer = ByteBuffer.allocate(128);
socketChannel.read(readBuffer);
StringBuffer stringBuffer = new StringBuffer();
readBuffer.flip();
while (readBuffer.hasRemaining()) {
stringBuffer.append((char) readBuffer.get());
}
System.out.println("从服务端接受到的数据:"+stringBuffer);
socketChannel.close();
}
}
package java_guide; import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel; public class WebServer {
public static void main(String[] args) throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress("127.0.0.1",3333));
SocketChannel socketChannel = serverSocketChannel.accept();
ByteBuffer writeBuffer = ByteBuffer.allocate(128);
writeBuffer.put("hello this is a message from server".getBytes());
writeBuffer.flip();
socketChannel.write(writeBuffer);
ByteBuffer readBuffer = ByteBuffer.allocate(128);
socketChannel.read(readBuffer);
StringBuffer stringBuffer = new StringBuffer();
readBuffer.flip();
while(readBuffer.hasRemaining()){
stringBuffer.append((char)readBuffer.get());
}
System.out.println("从客户端接收到的数据:"+stringBuffer);
socketChannel.close();
serverSocketChannel.close();
}
}
Selector(选择器)的使用方法介绍
1. Selector的创建
通过调用Selector.open()方法创建一个Selector对象,如下:
Selector selector = Selector.open();
2. 注册Channel到Selector
channel.configureBlocking(false); SelectionKey key = channel.register(selector, Selectionkey.OP_READ);
register() 方法的第二个参数。这是一个“ interest集合 ”,意思是在通过Selector监听Channel时对什么事件感兴趣。可以监听四种不同类型的事件:
Connect
Accept
Read
Write
通道触发了一个事件意思是该事件已经就绪。比如某个Channel成功连接到另一个服务器称为“ 连接就绪 ”。一个Server Socket Channel准备好接收新进入的连接称为“ 接收就绪”。一个有数据可读的通道可以说是“ 读就绪 ”。等待写数据的通道可以说是“ 写就绪 ”。
这四种事件用SelectionKey的四个常量来表示:
SelectionKey.OP_CONNECT SelectionKey.OP_ACCEPT SelectionKey.OP_READ SelectionKey.OP_WRITE
如果你对不止一种事件感兴趣,使用或运算符即可,如下:int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;
3. SelectionKey介绍
一个SelectionKey键表示了一个特定的通道对象和一个特定的选择器对象之间的注册关系。
key.attachment(); //返回SelectionKey的attachment,attachment可以在注册channel的时候指定。
key.channel(); // 返回该SelectionKey对应的channel。
key.selector(); // 返回该SelectionKey对应的Selector。
key.interestOps(); //返回代表需要Selector监控的IO操作的bit mask
key.readyOps(); // 返回一个bit mask,代表在相应channel上可以进行的IO操作。
三 模板代码
一个服务端的模板代码:
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.socket().bind(new InetSocketAddress("localhost", 8080));
ssc.configureBlocking(false);
Selector selector = Selector.open();
ssc.register(selector, SelectionKey.OP_ACCEPT);
while(true) {
int readyNum = selector.select();
if (readyNum == 0) {
continue;
} Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> it = selectedKeys.iterator(); while(it.hasNext()) { SelectionKey key = it.next(); if(key.isAcceptable()) { // 接受连接 } else if (key.isReadable()) { // 通道可读 } else if (key.isWritable()) { // 通道可写 } it.remove(); }
}
参考:微信公众号
NIO理解的更多相关文章
- JAVA IO 以及 NIO 理解
由于Netty,了解了一些异步IO的知识,JAVA里面NIO就是原来的IO的一个补充,本文主要记录下在JAVA中IO的底层实现原理,以及对Zerocopy技术介绍. IO,其实意味着:数据不停地搬入搬 ...
- Java NIO理解与使用
https://blog.csdn.net/qq_18860653/article/details/53406723 Netty的使用或许我们看着官网user guide还是很容易入门的.因为java ...
- java NIO理解分析与基本使用
我前段时间的一篇博客java网络编程--多线程数据收发并行总结了服务端与客户端之间的收发并行实践.原理很简单,就是针对单一客户端,服务端起两个线程分别负责read和write操作,然后线程保持阻塞等待 ...
- Java nio 理解
Java nio 称为Java new IO ,对Java io而言的.他有两个主要的概念:缓存.通道. 在程序中,数据的来源或写入,要么网络.要么硬盘.所有通道分为:文件通道.TCP通道.UDP通道 ...
- 第十二章 NIO
12.NIO 12.1 Java NIO 概述 1课时 12.2 Java NIO.2 之Path.Paths 与 Files 的使用 1课时 12.3 自动资源管理 1课时 12.4 缓冲区(Buf ...
- JAVA NIO 中的 zerocopy 技术提高IO性能
关于一篇更详细更好的介绍 ZeroCopy技术的文章,可参考:JAVA IO 以及 NIO 理解 这篇文章介绍了 zerocopy技术来提高Linux平台上的IO密集型的JAVA应用程序的性能. ze ...
- netty使用从0到1
本周强总在组内做了netty分享,内容相当不错,趁着这次分享记录的,以及以前研究,进行一下记录. java io形式存在三种,一种是BIO传统IO是阻塞IO,面向字符.字节服务都属于这一种.NIO官方 ...
- Netty学习路线
预研时间170517-170519 投入时间:约10h 理解度:入门①前置基础:了解基本网络协议和通信方式[图解HTTP]http://download.csdn.net/detail/niehanm ...
- 关于CPU的User、Nice、System、Wait、Idle各个参数的解释
使用Ganglia监控整个Hadoop集群,看到Ganglia采集的各种指标:CPU各个具体的指标含义解释如下: ①CPU(监测到的master主机上的CPU使用情况) 从图中看出,一共有五个关于CP ...
随机推荐
- AS400 printer setting
(1) CRTOUTQ OUTQ(TESTLIB/PRINTER2) (2) CRTDEVPRT ===> CRTDEVPRT DEVD(PRINTER2) DEVCLS(*LAN) TYPE( ...
- LibreOJ #115. 无源汇有上下界可行流
二次联通门 : LibreOJ #115. 无源汇有上下界可行流 /* LibreOJ #115. 无源汇有上下界可行流 板子题 我也就会写写板子题了.. */ #include <cstdio ...
- BZOJ 2038: [2009国家集训队]小Z的袜子
二次联通门 : BZOJ 2038: [2009国家集训队]小Z的袜子 /* BZOJ 2038: [2009国家集训队]小Z的袜子 莫队经典题 但是我并不认为此题适合入门.. Answer = ∑ ...
- Xmind8安装
现在新版安装极其简单.是deb安装包Xmind8安装小书匠 kindle 参照官网安装方法,在此记录下来,方便自己查找. 流程: 55ccaad0655d256ac5fb9fea8aa8569d.pn ...
- infiniband RDMA对比
- scala 递归读取文件夹下所有的指定后缀的文件
def getFile(file:File): Array[File] ={ val files = file.listFiles().filter(! _.isDirectory) .filter( ...
- C#中指针的简单使用
原来C#不仅仅支持和C/C++中指针(或者说是引用)很像的委托delegate,还支持在unsafe代码块中使用指针,从而写非托管的代码(人为不让垃圾回收机制来管理相应的内存).在unsafe中就可以 ...
- 快速打造自己的PHPStorm主题
---恢复内容开始--- 一个优雅和舒适的界面,可以增加过多写入代码的动力. Phpstorm小型的白色主题比较简陋.为了打造一个优雅和舒适的界面,我们安装一件叫Material Theme UI的插 ...
- 数据结构——KMP算法
算法介绍 KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法).KMP算法的核心是利用 ...
- 制作A4纸打印的网页像素大小设置(转)
公司内做系统,要用A4纸打印东西,A4纸标准时mm,换算成像素不知道.网上找找,找到一篇文章,转一下,备用. A4纸的尺寸是210mm*297mm,也就是21.0cm*29.7cm,而1英寸=2.54 ...