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是抽象类)。需要通过 InputStreamOutputStreamRandomAccessFile 获取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(); }
}

参考:微信公众号

最新文章

  1. 15个关于Chrome的开发必备小技巧[译]
  2. 每日设置Bing首页图片为壁纸
  3. glob模式
  4. 0020 Java学习笔记-面向对象-变量
  5. 150922-写写博客监督下不自觉的自己-PPT,Linux,HTML
  6. 第一篇 UEditor入门部署和体验
  7. iOS - (利用/调用系统定位获取当前经纬度与地理信息)
  8. Squid Proxy Server 3.1
  9. Linux Tcpdump 使用举例 ---持续更新
  10. oc-27-@property的参数
  11. C# and JSON
  12. 移动设备日期选择插件(基于JQUERY)
  13. Elasticsearch相关配置(二)
  14. 微信公众号、H5、APP三者各有什么优势?
  15. 网络拓展知识 ACL NAT IPv6
  16. 优化设计提高sql类数据库的性能
  17. Java 处理PDF图章(印章)——图片图章、动态图章
  18. [Linux] 搭建rsync服务端
  19. Excel2010隔行变色的实现方法 [也可套用格式即可]
  20. 大型运输行业实战_day11_1_aop理论与aop实际业务操作

热门文章

  1. 2019年京东 PHP工程师面试题
  2. start django project
  3. 贾扬清牛人(zz)
  4. centos7mongo集群
  5. ROS手动编写消息发布器和订阅器topic demo(C++)
  6. @ResponseBody 中文乱码 问题
  7. Dp优化之决策单调栈优化
  8. Docker Dockerfile 定制镜像
  9. java四种对象引用类型
  10. Lucene核心数据结构——FST存词典,跳表存倒排或者roarning bitmap 见另外一个文章