本帖最后由 大蓝鲸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虚拟机之外.
|