黑马程序员技术交流社区
标题: 【南京校区】关于IO的底层探讨BIO,NIO,AIO(一) [打印本页]
作者: 大蓝鲸Java 时间: 2017-11-29 00:59
标题: 【南京校区】关于IO的底层探讨BIO,NIO,AIO(一)
本帖最后由 大蓝鲸Java 于 2017-12-1 12:32 编辑
BIO : blocking IO 普通的IO
NIO : Non-blocking IO (new IO) JDK 1.4 出现的
NIO2: NIO二代,又名 AIO. JDK1.7以后出现的
NIO 跟 IO 相同的 都是读写操作.
不同的就是读写的方式是不一样的
IO 读写是面向于流来实现的
NIO 读写是面向于通道,面向缓冲区的. 提高了我们程序的效率
缓冲区: ByteBuffer
ShortBuffer
IntBuffer
LongBuffer
FloatBuffer
DoubleBuffer
CharBuffer
除了 boolean,其他7种基本数据类型都有其对应的缓冲区
其中ByteBuffer是用的最多的.
因为IO 操作的更多的是字节数据.
关于NIO学习,最重要的:
1,缓冲区
2,通道
3,选择器
1,缓冲区:
在底层其实就是一个数组.
capacity: 容量
limit:可操作到哪个索引
position:当前准备操作的索引
mark:相当于一个标记,用来记录当前position的值
reset:如果position的值发生变化了,那么通道reset可以反馈mark记录的那个值
//测试缓冲区代码
// 创建一个缓冲区
ByteBuffer buff = ByteBuffer.allocate(1024);
// 因为此时缓冲区正准备往里存数据
// 所以容量为1024
System.out.println(buff.capacity());// 1024
// 可以被使用1024
System.out.println(buff.limit());// 1024
// 当前要往0索引存
System.out.println(buff.position());// 0
buff.put("abcde".getBytes());
// 所以容量为1024
System.out.println(buff.capacity());// 1024
// 可以被使用1024
System.out.println(buff.limit());// 1024
// 当前要往0索引存
System.out.println(buff.position());// 3
buff.flip();// 切换读写模式
// 要开始往从这个缓冲区中取数据了
// 容量为1024
System.out.println(buff.capacity());// 1024
// 因为只存了3个字节,所以可以被操作的索引就是3
System.out.println(buff.limit());// 3
// 当前要从0索引开始读了.
System.out.println(buff.position());// 0
buff.mark();
byte[] bys = new byte[2];
buff.get(bys);// 读了两个字节
System.out.println(new String(bys));
System.out.println(buff.capacity());// 1024
// 因为只存了5个字节,所以可以被操作的索引就是5
System.out.println(buff.limit());// 5
// 当前要从2索引开始读了.
System.out.println(buff.position());// 2
System.out.println("--------------------------");
buff.reset();
buff.get(bys);// 读了两个字节
System.out.println(new String(bys));
System.out.println(buff.capacity());// 1024
// 因为只存了5个字节,所以可以被操作的索引就是5
System.out.println(buff.limit());// 5
// 当前要从2索引开始读了.
System.out.println(buff.position());// 2
2,通道
FileChannel 专门用于本地文件数据传输
SocketChannel 用于TCP
ServerSocketChannel 用于TCP
DatagramChannel 用于UDP
以 FileInputStream 为例,获取一个通道.
FileInputStream fis = new FileInputStream("a.txt");
fis.getChannel(); //获取一个通道
FileOutputStream fos = new FileOutputStream("copy.avi");
fos.getChannel();// 获取一个通道
利用通道,进行复制
示例代码:
FileInputStream fis = new FileInputStream("数据源");
FileOutputStream fos = new FileOutputStream("目的地");
FileChannel inChannel = fis.getChannel();
FileChannel outChannel = fos.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(8192);
while ((inChannel.read(buffer)) != -1) {
buffer.flip();
outChannel.write(buffer);
buffer.clear();
}
inChannel.close();
outChannel.close();
fis.close();
fos.close();
3,到这里大家不仅疑惑,BIO,和NIO并没有体现出NIO的效率高的问题
这个是因为,缓冲区又分为:直接缓冲区,非直接缓冲区
在上面的案例中,我们是直接 new 出来的数组.所以该数组在我们内存的堆中.
又得引出一个新的内容:
非直接缓冲区:把缓冲区创建在JVM虚拟机中.多了一个拷贝的操作
直接缓冲区:把缓冲区直接创建在内存中,不归虚拟机管了.
所以如果想利用NIO 提高读写的效率,那么就要结合直接缓冲区的操作
FileChannel inchannel = FileChannel.open(Paths.get("数据源), StandardOpenOption.READ);
FileChannel outchannel = FileChannel.open(Paths.get("目的地"),StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);
//底层创建一个直接缓冲区.用这个缓冲区在通道进行传输
inchannel.transferTo(0, inchannel.size(), outchannel);
inchannel.close();
outchannel.close();
总结:
通道就是用来连接数据源和目的地的.本身不传递数据,是通过通道里面的缓冲区进行传输的
缓冲区分直接缓冲区和非直接缓冲区
其中如果想提高效率,那么可以使用直接缓冲区,将缓冲区创建在系统本地物理内存,也就是在JVM虚拟机之外.
作者: 秒杀女神 时间: 2017-12-1 12:16
点个赞!
作者: 郭俊峰老师 时间: 2017-12-1 12:19
对底层有一定研究啊
作者: 王哈哈 时间: 2017-12-1 12:58
真的强!
作者: 阿胡婷婷 时间: 2017-12-1 12:58
点个赞
作者: 大蓝鲸Java 时间: 2017-12-1 12:58
自己顶自己
作者: 唐杰 时间: 2017-12-1 13:01
666,学习了。这解析很透彻。
作者: 大蓝鲸Java 时间: 2017-12-1 13:01
谢谢各位,南京校区教研部会写出更多的干货。
作者: 379177926 时间: 2017-12-1 13:05
nio面试的时候还是很喜欢问的
作者: 无敌小金刚 时间: 2017-12-1 13:15
{:8_474:}{:8_474:}
作者: 飞翔的刺头 时间: 2017-12-1 13:20
还属于小白。。。
作者: 海域王魂 时间: 2017-12-1 13:21
牛逼 虽然不会Java 但是感觉好厉害的样子
作者: @狂奔 时间: 2017-12-1 13:37
技术大牛,低层了解得好深。
作者: 小许同学 时间: 2017-12-1 13:47
厉害厉害!!!!
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |