1.IO与NIO区别
NIO | IO |
面向流 | 面向缓冲 |
阻塞IO | 非阻塞 |
无 | 选择器 |
2.三个属性
2.1 capacity:Buffer的内存固定的一个大小值,一般创建Buffer时初始化写入
2.2 position在读和写情况的分析:
1)写数据到Buffer中时,position表示写入数据的当前位置。position的初始值为0.当一个byte、long等数据写到Buffer后, position会向下移动到下一个可插入数据的Buffer单元。position最大可为capacity – 1(因为position的初始值为0).
2)读数据到Buffer中时,position表示读入数据的当前位置,如position=2时表示已开始读入了3个byte,或从第3个byte开始读取。通过ByteBuffer.flip()切换到读模式时position会被重置为0,当Buffer从position读入数据后,position会下移到下一个可读入的数据Buffer单元。
2.3 limit在读和写情况的分析:
1)写数据时,limit表示可对Buffer最多写入多少个数据。
2)读数据时,limit表示Buffer里有多少可读数据(not null的数据),因此能读到之前写入的所有数据
2.4 demo
import java.nio.ByteBuffer;
public class Test01 {
public static void main(String[] args) {
//创建缓冲区,最大为1024,即capacity=1024
ByteBuffer bb = ByteBuffer.allocate(1024);
//输出属性
System.out.println(bb.limit()); //实际可写入大小
System.out.println(bb.capacity()); //最大大小
System.out.println(bb.position()); //当前处理位置
//放入数据
System.out.println("------------放入数据");
bb.put("abcd1234".getBytes());
//输出属性
System.out.println(bb.limit()); //当写入的时候表示最多可以写入的数据量,此时为1024
System.out.println(bb.capacity()); //最大大小
System.out.println(bb.position()); //当前处理位置
//输出
System.out.println("-------------输出数据");
bb.flip();//将position位置重置为0,下面会做比较
byte[] b = new byte[bb.limit()]; //通过flip重置position位置后,此时的limit表示缓冲区可读数据的长度,此时limit=8
bb.get(b);
System.out.println(new String(b,0,bb.limit()));
//重复读取缓冲区数据
System.out.println("------------重复读数据");
bb.rewind();//重置下面会做比较
byte[] b1 = new byte[bb.limit()];
bb.get(b1);
System.out.println(new String(b1,0,bb.limit()));
//清空缓冲区
System.out.println("--------清空缓冲区");
bb.clear();
System.out.println(bb.limit());
System.out.println(bb.capacity());
System.out.println(bb.position());
System.out.println((char)bb.get());//仍可以读出数据,应为clear方法只是单纯的将三个属性重置,数据并没用清除
}
}
2.5 clear、flip、rewind 区别
2.5.1 clear源码
public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
}
clear方法将position重置为0,将可读写范围limit设置为最大范围capacity;
2.5.2 flip
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
将可读写范围设置为position的值,这样在读操作时,limit的值就是缓冲区中可以读写数据的大小。
将position的值重置。
2.5.3 rewind
public final Buffer rewind() {
position = 0;
mark = -1;
return this;
}
rewind方法只是简单的将position的值重置,这样可以从缓冲区开始位置读取数据。
2.6 mark()和reset()方法
2.6.1 mark():标记当前position的位置,reset()将position返回到标记的位置。
import java.nio.ByteBuffer;
public class Test02 {
public static void main(String[] args) {
ByteBuffer bb = ByteBuffer.allocate(10);
bb.put("abcd".getBytes());
bb.flip();
byte[] b = new byte[2];
bb.get(b,0,2);//取出两个字节
System.out.println("position:"+bb.position());
bb.mark();//标记当前position的位置
System.out.println(new String(b,0,2));
bb.get(b,0,2);//再取出两个字节
System.out.println("再取出两个字节后的position:"+bb.position());
bb.reset();//返回标记的position位置
System.out.println("返回后的position:"+bb.position());
}
}
2.7 直接缓冲区和非直接缓冲区复制文件
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import org.junit.Test;
public class Test03 {
/**
* 通过管道复制文件,--非直接缓冲区
* 思路是:
* 1.创建源文件的输入流和目标文件的输出流
* 2.分别冲输入输出流中创建各自的管道
* 3.创建缓冲区,通过缓冲区,从输入管道中读取源文件内容到缓冲区中,再将缓冲区中的内容写道输出管道中
* 4.关闭相应的资源
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//创建输入流,读取图片
FileInputStream is = new FileInputStream("1.jpg");
//创建输出流,输出图片
FileOutputStream os = new FileOutputStream("2.jpg");
//创建通道
FileChannel inChannel = is.getChannel();
FileChannel outChannel = os.getChannel();
//通过缓冲区将数据从输入通道,读到输出通道
ByteBuffer bb = ByteBuffer.allocate(1024);
while(inChannel.read(bb) != -1){
bb.flip();//上面写入缓冲区后,需要重置Position位置,使下面可以从头开始读缓冲区
outChannel.write(bb);
bb.clear();//上面读后,需要重置,使下一次可以从头写入缓冲区
}
//关闭
outChannel.close();
inChannel.close();
os.close();
is.close();
}
/**
* 通过管道复制文件 ----直接缓冲区
* 思路:
* 1.通过工厂方法创建源文件和目标文件的管道
* 2.创建各自的映射缓冲区
* 3.从读缓冲区中读取数据到写入缓冲区中
* @throws IOException
*/
@Test
public void test() throws IOException{
//直接创建文件管道
FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
FileChannel outChannel = FileChannel.open(Paths.get("3.jpg"), StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);
//创建文件映射
MappedByteBuffer inmap = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());
MappedByteBuffer outmap = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size());
//操作缓冲区
byte[] b = new byte[inmap.limit()];
inmap.get(b);
outmap.put(b);
//关闭资源
outChannel.close();
inChannel.close();
}
}
2.8 多缓冲区读取文件
import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class Test04 {
/**
* 多缓冲区读取文件
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//创建文件输入流
//RandomAccessFile file = new RandomAccessFile("test01.txt", "rw");
FileInputStream file = new FileInputStream(new File("test01.txt"));
//创建管道
FileChannel channel = file.getChannel();
//创建缓冲区
ByteBuffer buf1 = ByteBuffer.allocate(100);
ByteBuffer buf2 = ByteBuffer.allocate(1024);
//缓冲区数组
ByteBuffer[] bs = new ByteBuffer[]{buf1,buf2};
//从管道读取数据到缓冲区中
channel.read(bs);
//读出缓冲区内容
System.out.println(new String(buf1.array(),0,buf1.limit()));
System.out.println("------------------");
System.out.println(new String(buf2.array(),0,buf2.limit()));
}
}