所有的 IO 在NIO 中都从一个Channel 开始。 数据从Channel读取到Buffer,或从Buffer写到Channel。
FileInputStream获取的FileChannel只能读;而FileOutputStream获取的FileChannel只能写。
Channel通过传统的节点InputStream、OutputStream的getChannel()方法返回对应的Channel。不同节点流获得的Channel不一样。
格式:MapByteBuffer map(FileChannel.MapMode mode, long position, long size); 第一个参数执行映射时的模式,有只读、读写等模式;第二、三个参数用于控制Channel中映射成ByteBuffer的数据。
示例:
import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public class A { public static void main(String[] args) throws IOException { //创建一个RandomAccessFile对象 RandomAccessFile file = new RandomAccessFile("D://java/test1.txt","r"); //使用FileChannel读取数据到Buffer中 FileChannel channel1 = file.getChannel(); ByteBuffer buf = ByteBuffer.allocate(10); int bytesRead = channel1.read(buf); while(bytesRead!=-1){ System.out.println("Read"+bytesRead); buf.flip();//切换 while(buf.hasRemaining()){ System.out.print((char) buf.get()+" "); } buf.clear(); bytesRead = channel1.read(buf); System.out.println(); } file.close(); } }运行结果:
分析: 1、使用FileChannel channel1 = file.getChannel();创建Channel对象; 2、分配一个Buffer:长度为48个字节 ByteBuffer buf = ByteBuffer.allocate(48); 3、调用Channel的read()方法从FileChannel中读取数据。 int bytesRead = Channel.read(buf); 4、read()方法返回的int值表示了有多少字节被读到了Buffer中。如果返回-1,表示到了文件末尾。 5、循环打印读出来的数据: while(buf.hasRemaining()){ System.out.print((char) buf.get()+” “); } 6、关闭FileChannel:file.close();
程序执行的功能是将文件中的全部数据映射到Buffer中,并复制到另一个文件中。 程序中①②两条语句分别使用了FileInputStream、FileInputStream来获取FileChannel。程序后面的System.out.println(charBuffer);语句将Buffer中数据输出到控制台。
运行结果:控制台输出的结果 接下来我们再看一下文件中存入的数据:
1、可以看到文件中存入的并不是我们在程序中定义的字符数组或整形数组,而是两个相同的字符串;通过对比,原来写入到文件中的定义的数组作为ASCII值对应的字符。
2、我们还可以看到,无论定义的是字符数组char[],还是整形数组int[],写到文件中的均是字符串。这引起了我的注意,查看FileChannel中的write()方法,可以发现,write()方法只可以写ByteBuffer[]类型的数组,意思是只能将字符串写入到文件中。如下图所示。
在这七种类型中,只有CharBuffer和ByteBuffer两种类型比较常用。 其中只有ByteBuffer才可以通过allocateDirect()方法来直接创建Buffer。而其他的只能通过allocate()方法来创建Buffer。
1、写入数据: 两种方法:put()和read() 2、调用flip()方法:从写模式切换到读模式
3、读取数据 4、清空缓冲区:clear()方法或compact()方法
clear()方法会清空整个缓冲区。 compact()方法只会清除已经读过的数据。任何未读的数据都被移到缓冲区的起始处,新写入的数据将放到缓冲区 未读数据的后面。
示例:
import java.nio.CharBuffer; public class BufferTeat { public static void main(String[] args) { //创建Buffer CharBuffer buff = CharBuffer.allocate(8); System.out.println("capacity:" + buff.capacity()); System.out.println("limit:" + buff.limit()); System.out.println("position:" + buff.position()); //放入元素 buff.put('a'); buff.put('b'); buff.put('c'); System.out.println("加入三个元素后,position = " + buff.position()); //调用filp()方法,将Buffer中没有数据的空间封印起来,避免Buffer读出null buff.flip(); System.out.println("执行filp()方法后,limit = " + buff.limit()); System.out.println("position = " + buff.position()); //取出第一个元素 System.out.println("第一个元素(position = 0):" + buff.get()); System.out.println("取出第一个元素后,position = " + buff.position()); //调用clear()方法 buff.clear(); System.out.println("执行clear()后,limit = " + buff.limit()); System.out.println("执行clear()后,position = " + buff.position()); //根据索引去数据,不会影响Buffer的position值 System.out.println("执行clear()后,缓冲区内容并没有被清空: 第三个元素为: " + buff.get(2)); System.out.println("执行绝对读取后,position = " + buff.position()); } }运行结果: 分析: 1、CharBuffer buff = CharBuffer.allocate(8); 分配8个字节的缓冲区,capacity的值为8;limit的值为8;position的值为0。 2、放入三个元素后,position的值变为3,指明下一个可被写入的缓冲区位置索引;capacity和limit的值仍为3。 3、执行filp()方法,从写模式切换到读模式,将limit的值设为position处,把position指向0;此时limit=3,而position=0。 4、第一个元素为a; 5、取出第一个元素a后,position后移一位,指向1。 6、调用clear()方法:将position设为0;limit设为与capacity相等。所以执行方法clear()后,position=0,limit=8;执行clear()方法,并没有清除缓冲区中的内容,通过读取缓冲区中的第三个元素可知,读取的第三个元素为c。
在这两天的IO学习中,可能是因为之前很少接触,导致这两天上课比较迷糊,学的很不深刻,对于IO、NIO这块儿还有很多方法都还不是很理解,希望在以后的学习中,能够将这些不理解的知识补充起来。