java NIO Buffer
1. 简介
Java NIO 中的 Buffer 用于和 NIO 通道进行交互。如你所知,数据是从通道读入缓冲区,从缓冲区写入到通道中的。
缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成 NIO Buffer 对象,并提供了一组方法,用来方便的访问该块内存。
2. Buffer的capacity,position和limit
对buffer的操作核心就是对position和limit指针位置的操作。
capacity
作为一个内存块,Buffer有一个固定的大小值,也叫“capacity”.你只能往里写capacity个byte、long,char等类型。一旦Buffer满了,需要将其清空才能继续写数据往里写数据。
position
当你写数据到Buffer中时,position表示当前的位置。初始的position值为0,当写入/读取一个数据的时候position会+1。position最大可为capacity – 1。
调用flip()切换读模式的时候,position会重置为0.
limit
在写模式下,Buffer的limit表示你最多能往Buffer里写多少数据。 写模式下,limit等于Buffer的capacity。
当切换Buffer到读模式时, limit表示你最多能读到多少数据。limit会被设置成之前的position值,换句话说,你能读到之前写入的所有数据。
3. Buffer的类型
Java NIO 有以下Buffer类型
ByteBuffer
MappedByteBuffer
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer
4. Buffer的基本用法
标准流程:
1 . 创建buffer,写入数据到Buffer
2 .调用flip()方法,将limit = position ,position = 0,切换读模式
3 .从Buffer中读取数据
4 .读取完成后调用clear()方法或者compact()方法,是指针复位,以备下次读取。
注意事项:
1 . flip()方法不能连续调用多次,否则指针会混乱
2 . clear()方法并不能真正清除数据,只是将指针复位,待下次写入数据时就可以覆盖原数据。如果需要连续写入,在第一次写入完成后调用mark()标记位置,然后在需要再次写入的时候调用reset()复位。
3 . Channel
read()方法是写入buffer,写入前应该是刚创建的buffer或者调用一次clear;
write()方法是读取buffer。读取前应该调用一次flip();
示例代码:
RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();
//create buffer with capacity of 48 bytes
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf); //read into buffer.
while (bytesRead != -1) {
//切换读模式
buf.flip(); //make buffer ready for read
while(buf.hasRemaining()){
System.out.print((char) buf.get()); // read 1 byte at a time
}
}
buf.clear();
aFile.close();
5.Buffer实用工具类
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.Calendar;
/**
* @author: zonglin_wu
* @Date: 2018/7/25 19:42
* @Description:
*/
public class ByteBufferUtil {
public static byte[] readByte(ByteBuffer byteBuffer){
byte[] b = null;
//为读者做准备,切换读模式
byteBuffer.flip();
b = new byte[byteBuffer.limit()];
byteBuffer.get(b);
//清楚标记位
byteBuffer.clear();
return b;
}
/**
* 读取byteBuffer数据,在方法调用之前不能调用filp()或者clear()之类的操作指针的函数
* @param byteBuffer
* @return
*/
public static String readString(ByteBuffer byteBuffer){
try {
byte[] b = readByte(byteBuffer);
String s = new String(b, "UTF-8");
return s;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
/**
* 一次性写入,每次从头写入,写入完成后切换读模式。
* @param byteBuffer
* @param data
*/
public static void onceWrite(ByteBuffer byteBuffer,String data){
try {
//写之前指针复位
byteBuffer.clear();
byteBuffer.put(data.getBytes("utf-8"));
byteBuffer.flip();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
/**
* 可以进行多次写入,指针不复位
* @param byteBuffer
* @param data
*/
public static void write(ByteBuffer byteBuffer,String data){
try {
byteBuffer.put(data.getBytes("utf-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
/**
* 可以进行多次写入,指针不复位
* @param data
*/
public static ByteBuffer write(String data){
ByteBuffer byteBuffer = ByteBuffer.allocate(data.getBytes().length);
try {
byteBuffer.put(data.getBytes("utf-8"));
return byteBuffer;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
/**
* 一次性写入,每次从头写入,写入完成后切换读模式。
* @param data
*/
public static ByteBuffer onceWrite(String data){
ByteBuffer byteBuffer = ByteBuffer.allocate(data.getBytes().length);
try {
byteBuffer.put(data.getBytes("utf-8"));
byteBuffer.flip();
return byteBuffer;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
}
上一篇: redux教程(二)redux的相关示例以及实现原理
下一篇: 简单介绍Java编程中的线程池