一、ByteBuffer类非实例的方法
ByteBuffer类提供了4个静态工厂方法来获得ByteBuffer的实例:
1、ByteBuffer allocate(int capacity) //创建一个指定capacity的ByteBuffer。
2、ByteBuffer allocateDirect(int capacity) //创建一个direct的ByteBuffer,这样的ByteBuffer在参与IO操作时性能会更好
3、ByteBuffer wrap(byte [] array)
4、ByteBuffer wrap(byte [] array, int offset, int length) //把一个byte数组或byte数组的一部分包装成ByteBuffer。(offset指偏移量)
注意:wrap方法是静态函数且只能接收byte类型的数据,任何其他类型的数据想通过这种方式传递,需要进行类型的转换。
ByteBuffer.allocateDirect分配的堆外内存不需要我们手动释放,而且ByteBuffer中也没有提供手动释放的API。
简单实例
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class Main{
public static void main(String[] args) throws IOException {
try {
// 文件进口
FileInputStream fileInputStream = new FileInputStream( "test.txt" );
FileChannel inChannel = fileInputStream.getChannel();
// 文件出口
FileOutputStream fileOutputStream = new FileOutputStream( "test_out.txt" );
FileChannel outChannel = fileOutputStream.getChannel();
// buffer(相当于运煤车)
ByteBuffer byteBuffer = ByteBuffer.allocate(10*1024*1024); //申请堆外内存10MB
// ByteBuffer byteBuffer = ByteBuffer.allocateDirect(10*1024*1024); // Direct Buffer的效率会更高。
long start = System.currentTimeMillis(); // 记录系统时间(毫秒)
while (true) {
int eof = inChannel.read(byteBuffer); //每次读取块大小的文件内容
if (eof == -1) break; // 通道已经被运煤车运光
byteBuffer.flip(); // 将缓冲区准备为数据传出状态
outChannel.write(byteBuffer);
byteBuffer.clear(); // 这个方法实际上也不会改变缓冲区的数据,而只是简单的重置了缓冲
// 区的主要索引值.不必为了每次读写都创建新的缓冲区,那样做会降低性能.相反,要重用现在的
// 缓冲区,在再次读取之前要清除缓冲区.
}
System.out.println("spending : " + (System.currentTimeMillis() - start));
inChannel.close(); // 山西煤矿停止出售煤炭资源
outChannel.close(); // 山东发电厂停止接收煤炭资源
}catch(IOException e){
System.out.println("IOException");
}
}
}
二、ByteBuffer类实例对象的方法
方法 | 说明 |
---|---|
limit(), limit(10) | 其中读取和设置这4个属性的方法的命名和jQuery中的val(),val(10)类似,一个负责get,一个负责set |
reset() | 把position设置成mark的值,相当于之前做过一个标记,现在要退回到之前标记的地方 |
clear() | position = 0;limit = capacity;mark = -1; 有点初始化的味道,但是并不影响底层byte数组的内容 |
flip() | limit = position;position = 0;mark = -1; 翻转,也就是让flip之后的position到limit这块区域变成之前的0到position这块,翻转就是将一个处于存数据状态的缓冲区变为一个处于准备取数据的状态 |
rewind() | 把position设为0,mark设为-1,不改变limit的值 |
remaining() | return limit - position;返回limit和position之间相对位置差 |
hasRemaining() | return position < limit返回是否还有未读内容 |
compact() | 把从position到limit中的内容移到0到limit-position的区域内,position和limit的取值也分别变成limit-position、capacity。如果先将positon设置到limit,再compact,那么相当于clear() |
get() | 相对读,从position位置读取一个byte,并将position+1,为下次读写作准备 |
get(int index) | 绝对读,读取byteBuffer底层的bytes中下标为index的byte,不改变position |
get(byte[] dst, int offset, int length) | 从position位置开始相对读,读length个byte,并写入dst下标从offset到offset+length的区域 |
put(byte b) | 相对写,向position的位置写入一个byte,并将postion+1,为下次读写作准备 |
put(int index, byte b) | 绝对写,向byteBuffer底层的bytes中下标为index的位置插入byte b,不改变position |
put(ByteBuffer src) | 用相对写,把src中可读的部分(也就是position到limit)写入此byteBuffer |
put(byte[] src, int offset, int length) | 从src数组中的offset到offset+length区域读取数据并使用相对写写入此byteBuffer |
简单实例
package src;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
/**
* Created by MilletPu on 2017/7/31.
*/
public class testByteBuffer {
public static void main(String []args){
try {
ByteBuffer buffer = ByteBuffer.allocate(100 * 1024); //申请堆外内存
//ByteBuffer buffer = ByteBuffer.allocateDirect(100*1024); // Direct Buffer的效率会更高。
//******************************* string 转 buffer ******************************/
String sendString = "你好,服务器. ";
//wrap:是把一个byte数组或byte数组的一部分包装成ByteBuffer。
ByteBuffer sendBuffer = ByteBuffer.wrap(sendString.getBytes("UTF-16"));
// 通道也就是FileChannel,可以由FileInputStream,FileOutputStream,RandomAccessFile,三个类来产生
// RandomAccessFile支持任意位置读写类
// RandomAccessFile的功能:1、读取任意位置的数据;2、追加数据;3、任意位置插入数据;
// 方法名: RandomAccessFile.getFilePointer() 作用: 返回文件记录指针的当前位置
// 方法名: RandomAccessFile.seek(long pos) 作用: 将文件记录指针定位到pos的位置
FileChannel socketChannel = (new RandomAccessFile("test.txt","r")).getChannel();
while(true){
int eof = socketChannel.read(sendBuffer);
if(eof==-1) break;
System.out.println(eof);
}
}catch (Exception ignored) {
System.out.println("IOException");
}
}
private byte[] getBytes (char[] chars) { //将字符转为字节(编码)
Charset cs = Charset.forName ("UTF-8");
CharBuffer cb = CharBuffer.allocate (chars.length);
cb.put (chars); // 将char[]对象放入CharBuffer中
cb.flip (); // 将缓冲区准备为数据传出状态
ByteBuffer bb = cs.encode (cb);
return bb.array();
}
private char[] getChars (byte[] bytes) { //将字节转为字符(解码)
Charset cs = Charset.forName ("UTF-8");
ByteBuffer bb = ByteBuffer.allocate (bytes.length);
bb.put (bytes);
bb.flip ();
CharBuffer cb = cs.decode (bb);
return cb.array();
}
}