1. 通道映射技术:
1) 其实就是一种快速读写技术,它将通道所连接的数据节点中的全部或部分数据直接映射到内存的一个Buffer中,而这个内存Buffer块就是节点数据的映像,你直接对这个Buffer进行修改会直接影响到节点数据,而这个Buffer也不是普通的Buffer,叫做MappedBuffer,即镜像Buffer,对该Buffer进行修改会直接影响到实际的节点(更新到节点);
2) 由于是内存镜像,因此处理速度非常快!!
3) map原型:MappedByteBuffer map(MapMode mode, long position, long size); // 将节点中从position开始的size个字节映射到返回的MappedByteBuffer中
4) mode印出来映射的三种模式,在这三种模式下得到的将是三种不同的MappedByteBuffer:三种模式都是Channel的内部类MapMode中定义的静态常量,这里以FileChannel举例
i. FileChannel.MapMode.READ_ONLY:得到的镜像只能读不能写(只能使用get之类的读取Buffer中的内容);
ii. FileChannel.MapMode.READ_WRITE:得到的镜像可读可写(既然可写了必然可读),对其写会直接更改到存储节点;
iii. FileChannel.MapMode.PRIVATE:得到一个私有的镜像,其实就是一个(position, size)区域的副本罢了,也是可读可写,只不过写不会影响到存储节点,就是一个普通的ByteBuffer了!!
5) 映射的规矩:
i. 使用InputStream获得的Channel可以映射,使用map时只能指定为READ_ONLY模式,不能指定为READ_WRITE和PRIVATE,否则会抛出运行时异常!
ii. 使用OutputStream得到的Channel不可以映射!!并且OutputStream的Channel也只能write不能read!
iii. 只有RandomAccessFile获取的Channel才能开启任意的这三种模式!
6) MappedByteBuffer的用法和普通的ByteBuffer一样,只不过它的功能被上述的映射规则所限制了,比如只读的就只能get不能put,可写的以及私有的put、get都能用;
7) 示例:只读映射
public class Test { public static void main(String[] args) throws IOException { File f = new File("out.txt"); try ( FileChannel fcin = new FileInputStream(f).getChannel(); FileChannel fcout = new FileOutputStream("a.txt").getChannel(); ) { MappedByteBuffer mbb = fcin.map(FileChannel.MapMode.READ_ONLY, 0, f.length()); Charset cn = Charset.forName("GBK"); System.out.println(cn.decode(mbb)); mbb.flip(); // 写出去之前要操作就绪 fcout.write(mbb); } } }
2. RandomAccessFile的通道映射可读可写:
1) RandomAccessFile也有getChannel方法获取相应的NIO通道;
2) 其实NIO通道映射技术最大的受益者就是RandomAccessFile了,因为RandomAccessFile本身就是可读可写I/O通吃,如果RandomAccessFile的节点文件映射到内存中,直接对内存镜像修改来更新文件节点那岂不是效率大大提高吗?
3) RandomAccessFile获取的通道同样是FileChannel,因此其使用上和之前讲过任何一个普通的Channel没有区别,映射map也是理所当然的一样;
4) 只不过其Channel在map时只读、读写、私有三种模式都可以使用,不像InputStream和OutputStream那样有种种约束;
!!只不过读写模式下,对内存镜像做出的修改会直接更新到节点文件!!
!!这里插播一个Channel常用的方法:long position(); // 获取当前操作到节点文件的哪个位置
5) 示例:将文件第一个字符改成“牛”,然后将改动好的整个文件内容复制一遍再追加到文件末尾!
public class Test { public static void main(String[] args) throws IOException { File f = new File("out.txt"); try ( FileChannel fc = new RandomAccessFile(f, "rw").getChannel(); ) { MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, f.length()); mbb.put("牛".getBytes()); // 注意是字节,一定要转换成字节才行,这里对镜像的修改直接生效到节点文件中了! fc.position(f.length()); // 定位到文件末尾 mbb.clear(); // 注意!一定要是clear,将limit定位到capacity!如果是flip则当前limit才在第二个字符位置! fc.write(mbb); } } }!!注意:flip和clear要灵活运用,要根据他们的定义来(limit、position的变化);