1、基本使用代码
- 向buffer写入数据,例如调用channelread(buffer)
- 调用flip()切换至读模式
- 从buffer读取数据,例如调用buffer.get()
- 调用clear() 或cornpact()切换至写模式
- 重复1-4
public static void main(String[] args) {
// FileChannel
// 1、输入输出流 2.RandomAccessFile data.txt
try(FileChannel channel = new FileInputStream("D:\\\\1zheng\\\\dai\\\\netty\\\\mode01\\\\data.txt").getChannel()){
// 准备缓冲区
ByteBuffer buffer = ByteBuffer.allocate(10); //10个字节
while (true) {
// 从channel 读取数据,向buffer写入
int read = channel.read(buffer);
log.debug("读取到的字节数:{}", read);
if (read == -1) break; //没有内容时退出
// 打印内容
buffer.flip(); //切换读模式
while (buffer.hasRemaining()) { //是否还有剩余数据
byte b = buffer.get();
log.debug("实际字节:{}", (char) b);
}
buffer.clear(); //切换写模式
}
}catch (IOException e){
}
}
ByteBuffer有以下重要属性
- capacity :容量
- position : 读写下标
- limit :读写限制
流程
2、ByteBuffer常见方法
分配空间
可以使用 allocate
方法为ByteBuffer分配内存,也可以使用*allocateDirect
方法*
allocate
:分配的是是java堆内存,读写效率低,受到GC的影响
allocateDirect
:直接内存,读写效率高(少一次拷贝),不会受到GC的影响,分配的效率低
读写操作
clear()
:从0下标开始写
cornpact()
:压缩已有的空间,从写入到的位置继续写
get()
:从position 位置开始读;
get(0)
:读取0下标的值;
rewind():把
position 移动到0下标;
mark()
:标记当前position 下标
reset()
:把
position移动到mark()标记的下标去;
字符串转换
put("hello".getBytes());
StandardCharsets.UTF_8.encode("hello");
ByteBuffer.wrap("hello".getBytes());
public static void main(String[] args) {
// 1、字符串转为ByteBuffer
ByteBuffer buffer = ByteBuffer.allocate(16);
buffer.put("hello".getBytes()); //该方法需要去手动转为读模式
buffer.flip();
System.out.println(buffer);
System.out.println((char) buffer.get());
// 下面两种方法可以自动转为读模式
ByteBuffer buffer2 = StandardCharsets.UTF_8.encode("hello");
System.out.println(buffer2);
System.out.println((char) buffer2.get());
ByteBuffer buffer1 = ByteBuffer.wrap("hello".getBytes());
System.out.println(buffer1);
System.out.println((char) buffer1.get());
// 2、把ByteBuffer转为字符串
String s = StandardCharsets.UTF_8.decode(buffer2).toString();
System.out.println(s);
}
分散读取,集中写入到磁盘
public static void main(String[] args) {
ByteBuffer buffer2 = StandardCharsets.UTF_8.encode("hello");
ByteBuffer buffer3 = StandardCharsets.UTF_8.encode("hello");
ByteBuffer buffer4 = StandardCharsets.UTF_8.encode("你好");
try(FileChannel channel = new RandomAccessFile("words2.txt","rw").getChannel()){
channel.write(new ByteBuffer[]{buffer2,buffer3,buffer4});
}catch (Exception e){}
}
解决网络编程中ByteBuffer
常见的粘包,半包问题
public static void main(String[] args) {
ByteBuffer buffer = ByteBuffer.allocate(32);
buffer.put("Hello,world\\nI'm zhangsan\\nHo".getBytes());
split(buffer); //会先把粘包的读取完
buffer.put("w are you?\\n".getBytes());
split(buffer); //最后在把半包的拼接读取掉
}
private static void split(ByteBuffer buffer) {
buffer.flip();
for (int i = 0; i < buffer.limit(); i++) {
// 通过\\n找到一条完整消息
if (buffer.get(i)=='\\n'){
int length = i+1-buffer.position();
// 创建指定大小的缓冲区
ByteBuffer target = ByteBuffer.allocate(length);
// 把完整数据写入新的ByteBuffer中
for (int j = 0; j < length; j++) {
target.put(buffer.get());
}
target.flip();
String s = StandardCharsets.UTF_8.decode(target).toString();
System.out.println(s);
System.out.println(buffer);
}
}
buffer.compact();
}