Buffer Writing and Reading
Buffers
Introducing Buffers
_buffer_存储固定数量的数据,它是我们和I/O服务打交道的媒介对象,主要供_channel_读写使用。
Buffer
具有四个属性:
- Capacity:该buffer能够存储的数据容量
- Limit:buffer中可供读写的上边界
- Position:位置指针,指示可以被读写的位置
- Mark:位置标记,回头用
Buffer and its Children
Buffer
方法:
Method | Description |
---|---|
Object array() | 如果该buffer背后是java数组,则返回该数组,否则抛异常 |
int arrayOffset() | 如果该buffer背后是java数组,则返回当前buffer所基于数组的位置偏移量 |
int capacity() | buffer |
Buffer clear() | 清空,position置0,limit置为capacity,放弃mark位置 |
Buffer flip() | 翻转,limit 置为当前的position,position置0 |
boolean hasArray() | 判断该buffer时候是语句java 数组的 |
boolean hasRemaining() | 当前position和limit的间隔 |
boolean idDirect() | 判断该buffer是否是直接字节缓冲,即不是基于java数组的 |
boolean isReadOnly | 只读 |
int limit() | limit位置 |
Buffer limit(int newLimit) | 设置limit位置 |
Buffer mark() | 标记位置 |
int position() | |
Buffer position(int newPositon) | 设置新位置 |
int remaining() | 空余容量 |
Buffer reset() | 重置,将position指向之前的mark位置 |
Buffer rewind() | 倒回,positon置0,放弃mark |
Buffer都不是线程安全的,小心使用。
Buffers in Depth
尽管Buffer有多种,如ByteBuffer
,CharBuffer
,DoubleBuffer
等,最基本的是ByteBuffer
。我们主要围绕ByteBuffer
来学习。
Buffer Creation
ByteBuffer
的创建方式:
- ByteBuffer allocate(int capacity):直接指定容量分配,基于数组的
- ByteBuffer allocateDirect(int capacity):分配一个指定容量的直接字节缓冲,不是基于数组的
- ByteBuffer wrap(byte[] array, int offset, int length):包裹一个数组进去
- ByteBuffer wrap(byte[] array):一样
几个put()
,getI()
方法。
Fliping Buffers
Marking Buffers
Buffer Subclass Operations
compact()
:将buffer中未写出的数据移到最头上
equals()
:只有buffer有相同元素类型,剩余元素相同,以及剩余元素内容相同才返回true
compareTo()
:比较剩余的元素序列,每个字节的比较
Byte Ordering大小端问题
Direct Byte Buffers
操作系统可以直接访问一个进程的地址空间,例如,操作系统可以直接访问JVM的进程地址空间,执行一个基于字节数组的数据传输操作。然而,JVM可能不是连续存储该字节数组的,或者说它的GC将该字节数组转移到了另一个位置。由于这些原因,就有了直接字节缓冲(direct byte buffer)。
直接字节缓冲直接与_channel_和本地代码交互,这是JVM操作I/O最有效的的方法。
当我们传递一个非直接字节缓冲,_channel_会创建一个直接字节缓冲,将非直接缓冲中的内容复制到直接字节缓冲区,然后在临时的直接字节缓冲区执行I/O操作,然后再将临时的直接字节缓冲区中的内容复制到非直接字节缓冲区,然后临时直接字节缓冲区会被GC收集掉。
直接字节缓冲区的创建是很昂贵的,因为JVM堆外面的内存需要系统来分配,初始化/清理这些内存会比在JVM内部要慢。