发布时间:2024-02-26 12:30
buffer缓冲区的一种,我们最常使用的
ByteBuffer正确使用姿势
ByteBuffer结构
buffer写入读取流程
limit
和capacity
一起在尾部,position
在头部position
一直后移,直到limit
为止flip()
切换读模式从buffer
里读取数据。此时limit
指针移动至position
位置表示只能读取到这儿,position
指针移至buffer头部从头部开始读取clear()
方法切换至写模式(如果还没读完),position
和limit
归为初始位置(头尾),后续从头开始写入(覆盖写)limit
之前(未读完)就要写入时,需要将未读完的数据(此时position
至limit
)保护起来,因此不能使用clear()
。此时需要调用compact()
方法,将未读完的数据整体前移,position
指针放在未读完数据尾部(limit
移至尾部),从这儿开始写入。ByteBuffer相关方法
allocate()
,返回堆内存对象HeapByteBuffer
,使用堆内存,读写效率较低,受到GC
影响allocateDirect()
,返回直接内存对象DirectByteBuffer
,使用直接内存(少一次拷贝),读写效率较高,分配内存较慢,不受GC
类型,要防止内存泄漏channel.read(buffer)
从通道读取数据写入bufferbuffer.put((byte)value)
直接往缓冲区放入数据channel.write(buffer)
读取buffer数据写入到通道buffer.get()
从buffer中读取一个字节数据,如果传参也可以读取多个buffer.get(i)
根据索引读取数据(不移动position
)buffer.rewind()
将position
置为0,remark
置为-1,下次重新从头开始读buffer.mark()
对position
位置加标记,与reset()
结合使用buffer.reset()
将position
重置到mark
位置字符串转ByteBuffer
getBytes()
方法,获取byte数组,再使用ByteBuffer
的put()
方法塞进去(注意我们自己put后未调用flip()
,buffer还处于写模式)nio
的StandardCharsets.UTF_8.encode("str")
,将字符串直接转为Bytebuffer
(此时已切换成读模式了)ByteBuffer
的wrap(byte[])
方法,里面的值,可以使用字符串的getBytes()
方法获取byte数组(此时已切换成读模式了)ByteBuffer转字符串
ByteBuffer
可以直接使用StandardCharsets.UTF_8.decode(buffer).toString()
转化为字符串代码demo
package org.yanyulin;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
/**
* NIO demo
* 从文件中读取内容
*/
public class NioDemo {
public static void main(String[] args) {
// readFile();
scatterRead();
}
/*
* 读取文件内容
*/
private static void readFile() {
try {
// 文件通道,从文件流获取通道
FileChannel fileChannel = new FileInputStream("E:\\nio.txt").getChannel();
// 准备缓冲区
ByteBuffer buffer = ByteBuffer.allocate(10);
StringBuilder builder = new StringBuilder();
// 如果数据未读取结束,一直读取下去
while (true) {
// 从channel里读数据,写入到buffer
int len = fileChannel.read(buffer);
// -1 则读取结束,否则是已读取的字符长度
System.out.println("len = " + len);
if (len == -1) {
break;
}
// 未读取完,切换读模式从buff中读取数据
buffer.flip();
// 按照字节读取buff里的数据
while (buffer.hasRemaining()) {
builder.append((char)buffer.get());
}
// 清空buff,方便后续读取继续往buff写数据,下面继续写模式
buffer.clear();
}
System.out.println(builder.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* 分散读取文件内容
**/
private static void scatterRead() {
try(FileChannel channel = new RandomAccessFile("E:\\split.txt", "rw").getChannel()){
ByteBuffer buffer1 = ByteBuffer.allocate(8);
ByteBuffer buffer2 = ByteBuffer.allocate(5);
ByteBuffer buffer3 = ByteBuffer.allocate(8);
channel.read(new ByteBuffer[]{buffer1, buffer2, buffer3});
buffer1.flip();
buffer2.flip();
buffer3.flip();
System.out.println(StandardCharsets.UTF_8.decode(buffer1));
System.out.println(StandardCharsets.UTF_8.decode(buffer2));
System.out.println(StandardCharsets.UTF_8.decode(buffer3));
} catch (IOException e) {
e.printStackTrace();
}
}
}