您当前的位置: 首页 > 学无止境 > 心得笔记 网站首页心得笔记
【第20章:Java新IO】_缓冲区与Buffer
发布时间:2021-01-20 18:33:03编辑:雪饮阅读()
新io缓冲区操作
以int型为例,新io缓冲区通过java.nio.IntBuffer类实例化实现
import java.nio.IntBuffer ;
public class Hello{
public static void main(String args[]) throws Exception {
IntBuffer buf = IntBuffer.allocate(10) ; // 准备出10个大小的缓冲区
System.out.print("1、写入数据之前的position、limit和capacity:") ;
System.out.println("position = " + buf.position() + ",limit = " + buf.limit() + ",capacty = " + buf.capacity()) ;
int temp[] = {5,7,9} ;// 定义一个int数组
buf.put(3) ; // 设置一个数据
buf.put(temp) ; // 此时已经存放了四个记录(3,5,7,9)
System.out.print("2、写入数据之后的position、limit和capacity:") ;
System.out.println("position = " + buf.position() + ",limit = " + buf.limit() + ",capacty = " + buf.capacity()) ;
/**
*重设缓冲区,可以理解为翻转、浏览整个区的每个元素,由于每次put之后
*position偏移量会变更,但是limit的值一直还是和capacty一样,不会动态改变,它只按设定的缓冲区大小为准
*若不翻转操作,则会导致读取缓冲区数据时候从当前position开始读取,以这里为例position目前为4,那么limit以缓冲区大小为准则为10,那么从4向10读取
*则会因为对应偏移量的值不存在而读取默认int类型值(即0),则读取出来的值就类似于“000000”
*另外读取的时候是从position处开始读取的,而不进行翻转操作,position也不是从0的位置开始的
*所以综合起来flip翻转操作主要的作用是重置position并计算正确的limit
*/
buf.flip() ;
// postion = 0 ,limit = 原本position
System.out.print("3、准备输出数据时的position、limit和capacity:") ;
System.out.println("position = " + buf.position() + ",limit = " + buf.limit() + ",capacty = " + buf.capacity()) ;
System.out.print("缓冲区中的内容:") ;
while(buf.hasRemaining()){
int x = buf.get() ;
System.out.print(x + "、") ;
}
}
};
主缓冲区与子缓冲区
import java.nio.IntBuffer ;
public class Hello{
public static void main(String args[]) throws Exception {
IntBuffer buf = IntBuffer.allocate(10) ;
//在主缓冲区中加入10个奇数
int mtemp[] = {1,2,3,4,5,6,7,8,9,10};
buf.put(mtemp) ;
// 定义子缓冲区
IntBuffer sub = null ;
// 需要通过slice() 创建子缓冲区
buf.position(2) ;
buf.limit(6) ;
sub = buf.slice() ;
for(int i=0;i<sub.capacity();i++){
int temp = sub.get(i) ;
sub.put(temp-1) ;
}
buf.flip() ; // 重设缓冲区
/*
*由于翻转只能让limit变成翻转之前的position并重置position,所以这里操作子缓冲区的时候进行了position操作,
*所以这里要读取主缓冲区的时候就需要单独设置下limit
*/
buf.limit(buf.capacity()) ;
System.out.print("主缓冲区中的内容:") ;
while(buf.hasRemaining()){
int x = buf.get() ;
System.out.print(x + "、") ;
}
System.out.println();
System.out.print("子缓冲区中的内容:") ;
sub.flip();
while(sub.hasRemaining()){
int x = sub.get() ;
System.out.print(x + "、") ;
}
}
};
D:\>javac Hello.java
D:\>java Hello
主缓冲区中的内容:1、2、2、3、4、5、7、8、9、10、
子缓冲区中的内容:2、3、4、5、
“子缓冲区可以修改数据”
import java.nio.IntBuffer ;
public class Hello{
public static void main(String args[]) throws Exception {
IntBuffer buf = IntBuffer.allocate(10) ;
int mtemp[] = {1,2,3,4,5,6,7,8,9};
buf.put(mtemp) ;
// 定义子缓冲区
IntBuffer sub = null ;
// 需要通过slice() 创建子缓冲区
buf.position(2) ;
buf.limit(6) ;
sub = buf.slice() ;
//定义一个临时缓冲区只为获取其大小大于上面定义的子缓冲区
IntBuffer tempSub = IntBuffer.allocate(10) ;
for(int i=0;i<sub.capacity();i++){
int temp = sub.get(i) ;
tempSub.put(temp-1) ;
}
//这样就实现了子缓冲区的扩容,否则直接增加会抛出越界异常
sub=tempSub;
//子缓冲区修改数据(新增数据)
sub.put(10);
buf.flip() ; // 重设缓冲区
buf.limit(buf.capacity()) ;
System.out.print("主缓冲区中的内容:") ;
while(buf.hasRemaining()){
int x = buf.get() ;
System.out.print(x + "、") ;
}
System.out.println();
System.out.print("子缓冲区中的内容:") ;
sub.flip();
while(sub.hasRemaining()){
int x = sub.get() ;
System.out.print(x + "、") ;
}
}
};
D:\>javac Hello.java
D:\>java Hello
主缓冲区中的内容:1、2、3、4、5、6、7、8、9、0、
子缓冲区中的内容:2、3、4、5、10、
创建只读子缓冲区
import java.nio.IntBuffer ;
public class Hello{
public static void main(String args[]) throws Exception {
IntBuffer buf = IntBuffer.allocate(10) ;
int mtemp[] = {1,2,3,4,5,6,7,8,9};
buf.put(mtemp) ;
IntBuffer read = buf.asReadOnlyBuffer() ;// 创建只读缓冲区
read.flip() ; // 重设缓冲区
System.out.print("主缓冲区中的内容:") ;
while(read.hasRemaining()){
int x = read.get() ;
System.out.print(x + "、") ;
}
read.put(30) ; // 修改,错误
}
};
D:\>javac Hello.java
D:\>java Hello
主缓冲区中的内容:1、2、3、4、5、6、7、8、9、Exception in thread "main" java.nio.ReadOnlyBufferException
at java.nio.HeapIntBufferR.put(HeapIntBufferR.java:148)
at Hello.main(Hello.java:17)
这里添加报错了,而且报错的不是越界错误,而是只读错误,这样就防止子缓冲区修改数据
创建直接缓冲区
在直接缓冲区中操作,系统会尽最大努力对其进行本机io操作,直接操作io
创建直接缓冲区用allocateDirect静态方法,以字节数据操作为例。
在Java中当我们要对数据进行更底层的操作时,一般是操作数据的字节(byte)形式,这时经常会用到ByteBuffer这样一个类。ByteBuffer提供了两种静态实例方式:
ByteBuffer.allocate()与ByteBuffer.allocateDirect()
为什么要提供两种方式呢?这与Java的内存使用机制有关。第一种分配方式产生的内存开销是在JVM中的,而另外一种的分配方式产生的开销在JVM之外,以就是系统级的内存分配。当Java程序接收到外部传来的数据时,首先是被系统内存所获取,然后在由系统内存复制复制到JVM内存中供Java程序使用。所以在另外一种分配方式中,能够省去复制这一步操作,效率上会有所提高。“可是系统级内存的分配比起JVM内存的分配要耗时得多”(根据数据所处环境与jvm的较近还是与系统内存较近),所以并非不论什么时候allocateDirect的操作效率都是最高的。
当操作数据量非常小时,两种分配方式操作使用时间基本是同样的,第一种方式有时可能会更快,可是当数据量非常大时,另外一种方式会远远大于第一种的分配方式。
创建直接缓冲区如:
import java.nio.ByteBuffer ;
public class Hello{
public static void main(String args[]) throws Exception {
//创建直接缓冲区
ByteBuffer buf = ByteBuffer.allocateDirect(10) ;
byte temp[] = {1,3,5,7,9} ; // 设置内容
buf.put(temp) ; // 设置一组内容
buf.flip() ;
System.out.print("主缓冲区中的内容:") ;
while(buf.hasRemaining()){
int x = buf.get() ;
System.out.print(x + "、") ;
}
}
};
D:\>javac Hello.java
D:\>java Hello
主缓冲区中的内容:1、3、5、7、9、
关键字词:java,缓冲区,Buffer