Buffer 类中几个重要的变量
- capacity就是Buffer它所能存放元素的个数。在Buffer创建的时候就已经确定了。
- limit JDK中的介绍是不能读或者写的第一个元素的下标索引。它不会为负数,或者超过capacity。
-
读 -> 写模式下: postion设置成limit,他会把limit设置成capacity 然后让postion++;
-
写 -> 读模式下: 它会把postion 赋值给limit 然后让position = 0 ; 读的最大值就是写入数据position。
- position 是下一个可以被读和写的元素的索引。不为负数 或者超过limit
特别的:每个原生类型都有与之对应的Buffer子类,比如IntBuffer,ByteBuffer,等等 除了boolean 。
Buffer的使用
读取文件:
public class NioTest2 {
public static void main(String[] args) {
try(FileInputStream fileInputStream = new FileInputStream("NioTest.txt");
FileChannel channel = fileInputStream.getChannel()){
ByteBuffer byteBuffer = ByteBuffer.allocate(512);
channel.read(byteBuffer);
byteBuffer.flip();
while (byteBuffer.remaining() > 0){
System.out.print((char) byteBuffer.get());
}
System.out.println();
}catch (IOException e){
e.printStackTrace();
}
}
}
写文件:
public class NioTest3 {
public static void main(String[] args) {
try(FileOutputStream fileOutputStream = new FileOutputStream("NioTest2.txt");
FileChannel channel = fileOutputStream.getChannel()){
ByteBuffer byteBuffer = ByteBuffer.allocate(512);
String data = "Hello world ";
byte[] buffer = data.getBytes();
for (int i = 0; i< buffer.length; i++){
byteBuffer.put(buffer[i]);
}
byteBuffer.flip();
channel.write(byteBuffer);
}catch (IOException e){
e.printStackTrace();
}
}
}
ByteBuffer的创建
创建HeapByteBuffer,它的数据是存在堆上的。
ByteBuffer byteBuffer = ByteBuffer.allocate(16);
它的实现:
public static ByteBuffer allocate(int capacity) {
if (capacity < 0)
throw new IllegalArgumentException();
return new HeapByteBuffer(capacity, capacity);
}
创建DirectByteBuffer
//创建
ByteBuffer directBuffer = ByteBuffer.allocateDirect(16);
//实现
public static ByteBuffer allocateDirect(int capacity) {
return new DirectByteBuffer(capacity);
}
DirecByteBuffer 创建的数据是在直接内存区域,堆外内存:可以减少一次系统空间到用户空间的拷贝。但创建和销毁成本高,不宜管理,通常会用内存池来管理。
通常情况下,操作系统的一次写操作分为两步:
将数据从用户空间拷贝到系统空间(即从 JVM 内存拷贝到系统内存)。
从系统空间往网卡写。
同理,读操作也分为两步:
将数据从网卡拷贝到系统空间;
将数据从系统空间拷贝到用户空间
Buffer的零拷贝
下面这段话是对Buffer类中的address 属性的描述。
// Used only by direct buffers
// NOTE: hoisted here for speed in JNI GetDirectBufferAddress
long address;
它的意思就是当使用DirectBuffer 的时候这个地址指向了堆外内存,从而避免了从堆外内存拷贝到堆上的过程,我们把这个称之为zero copy。