资讯专栏INFORMATION COLUMN

Java IO (四) NIO

zengdongbao / 486人阅读

摘要:前面说的输入输出流都是阻塞式的而且传统的输入输出流都是通过字节的移动来处理即使不直接处理字节底层还是依赖字节处理也就是说面向输输出系统一次只能处理一个字节所以效率并不高新概述新使用不同的方式来处理输入输出采用内存映射文件的方式来处理输入输出

前面说的输入输出流都是阻塞式的.而且传统的输入输出流都是通过字节的移动来处理(即使不直接处理字节,底层还是依赖字节处理),也就是说面向输输出系统一次只能处理一个字节,所以效率并不高.

新IO概述

新IO使用不同的方式来处理输入输出.采用内存映射文件的方式来处理输入输出.它将文件的一段区域映射到内存中,像访问内存一样访文件(模拟了操作系统上虚拟内存的概念). NIO中主要包包括:

java.nio 和Buffer相关的类

java.nio.channels 包括Channel和Selector相关类

java.nio.charset 和字符集相关的类

java.nio.charset.spi 提供字符集服务的相关类

Channel(通道)和Buffer(缓冲)是新IO中的两个核心对象,Channel是对传统输入输出系统的模拟.新IO系统中所有数据都要通过通道传输;Channel与传统的InputStream,OutputStream最大区别在于提供了一个map方法,通过该map方法可以直接将"一块数据"映射到内存中.如果说传统的输入输出是面向流的处理,而新IO则是面向块的处理.

Buffer可以被理解成一个容器,本质是一个数组,发送到Channel中所有对象都必须首先放到Buffer中,从而Channel的读数据也必须先读到Buffer中.Buffer允许一次次的取数据,也允许使用Channel直接将文件的某块映射成Buffer.

Buffer

结构上看,Buffer像一个数组,保存多个类型的相同数据.Buffer是一个抽象类.最常用子类是ByteBuffer,可在底层字节数组上做get/set操作.除ByteBuffer之外,对应其他基本数据类型(boolean除外)都有相对应的Buffer,ByteBuffer,CharBuffer,CharBuffer,ShortBuffer,IntBuffer等.这些类除了ByteBuffer之外,都采用类似或相同的方法来管理数据.只是各自管理的对象不同而已.这些Buffer都没有提供构造器,通过如下方法得到一个Buffer对象:

static XxxBuffer allocate(int capacity) 创建一个容量为capacity的XxxBuffer对象

实际中使用较多的是ByteBufferCharBuffer.其他Buffer子类则较少使用.其中ByteBuffer的子类MappedByteBuffer,它用于表示Channel将磁盘文件的全部或部分映射到内存中得到的结果,通常MapByteBuffer对象由Channelmap对象返回.

Buffer中三个重要概念

容量(capacity) 缓冲区容量,表示该Buffer的最大数据容量.即最多可以存储多少数据.容量不能为负值,创建后也不可改变.

界限(limit) 第一个不应该被读出或者写入的缓冲区位置索引.limit后的位置既不可被读取,也不可被写.

位置(position) 用于指明下一个可以被读出的或写入缓冲区位置索引(类似IO流中的记录指针).Buffer从Channel读取数据时,position的位置等于恰好已经读了多少数据,创建Buffer对象时,position为0,从Channel读取了2个数据,position为2,指向Buffer中的第3的位置(第一个索引为0).

此外Buffer还支持一个可选标记mark,该mark允许直接将position指定位到mark处.这些值满足如下关系:0 <= mark <= position <= limit <= capacity

Buffer的主要作用就是装载数据,然后输出数据.开始时Buffer的position为0,limit为capacity.程序不断调用put向Buffer中放入数据(或从channel获取数据),每放入一些数据,position向后移动一些位置.

当Buffer装入数据结束后,调用filp方法,该方法将limit设置为position所在位置,将position设置为0.这样使得从Buffer中读取数据总是从0开始.读完所有装入的数据即结束.也就是说.Buffer调用filp后,Buffer为输出数据做好了准备.

当Buffer输出数据结束后,调用clear方法.将position置为0,将limit置为capacity,这样为再次向Buffer中装载数据做好准备.

Buffer中的常用方法: * int capacity() 返回Buffer的capacity大小 * boolean hasRemaining() 判断当前位置(position)和界限(limit)之间是否还有元素可供处理. * int limit() 返回Buffer的界限(limit)的位置 * Buffer limit(int newLt) 重新设置界限(limit)的值,并返回一个具有新的limit的缓冲区对象. * Buffer mark() 设置Buffer的mark的位置,只能在0和position之间. * int position 返回当前Buffer中的当前位置. * Buffer position(int newPs) 设置Buffer的新位置,并返回一个具有改变position后的Buffer对象. * int remaining() 返回当前位置和界限(limit)之间的元素个数 * Buffer reset() 将位置(position)转到mark所在的位置 * Buffer rewind() 将位置(position)设置为0,取消mark.

之外Buffer的所有子类还支持put/get方法.对Buffer进行数据的放入和取出.使用put/get来访问Buffer中数据时,分为绝对和相对两种: * 相对(Relative) 从Buffer当前位置读取或写入数据,然后将位置(position)的值按处理元素个数增加. * 绝对(Ansolut) 直接根据索引来向Buffer中读取或写入数据,使用绝对方式来访问Buffer里的数据,并不会影响position的值.

//省略代码
        CharBuffer cbuf = CharBuffer.allocate(8);
        System.out.println("capacity:"+ cbuf.capacity());
        System.out.println("limit" + cbuf.limit());
        System.out.println("position:"+ cbuf.position());

        cbuf.put("a");
        cbuf.put("b");
        cbuf.put("c");

        System.out.println("加入三个元素后,position:" + cbuf.position());
        cbuf.flip();
        System.out.println("执行filp,limit:" + cbuf.limit());
        System.out.println("position:" + cbuf.position());

        //取出第一个元素
        System.out.println("取出第一个元素:" + cbuf.get());
        System.out.println("取出第一个元素后,position:" + cbuf.position());
        cbuf.clear();
        //limit置为capacity
        System.out.println("执行clear后,limit:" + cbuf.limit());
        //capacity置0
        System.out.println("执行clear后,position:" + cbuf.position());
        //clear方法不清除缓冲区(buffer)中数据
        System.out.println("执行clear后,缓冲区内容没有被清除:" + cbuf.get(2)); 
        //绝对读取不影响position位置
        System.out.println("执行绝对读取后,position:" + cbuf.position()); 
//省略代码
Channel

//待更新

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64441.html

相关文章

  • Java IO之NIO

    摘要:上篇说了最基础的五种模型,相信大家对相关的概念应该有了一定的了解,这篇文章主要讲讲基于多路复用的。 上篇说了最基础的五种IO模型,相信大家对IO相关的概念应该有了一定的了解,这篇文章主要讲讲基于多路复用IO的Java NIO。 背景 Java诞生至今,有好多种IO模型,从最早的Java IO到后来的Java NIO以及最新的Java AIO,每种IO模型都有它自己的特点,详情请看我的上...

    pingink 评论0 收藏0
  • Java NIO 概览

    摘要:线程之间的切换对于操作系统来说是昂贵的。因此,单线程可以监视多个通道中的数据。当方法返回后,线程可以处理这些事件。 一 NIO简介 Java NIO 是 java 1.4 之后新出的一套IO接口,这里的的新是相对于原有标准的Java IO和Java Networking接口。NIO提供了一种完全不同的操作方式。 NIO中的N可以理解为Non-blocking,不单纯是New。 它支持面...

    chemzqm 评论0 收藏0
  • Java NIO浅析

    摘要:阻塞请求结果返回之前,当前线程被挂起。也就是说在异步中,不会对用户线程产生任何阻塞。当前线程在拿到此次请求结果的过程中,可以做其它事情。事实上,可以只用一个线程处理所有的通道。 准备知识 同步、异步、阻塞、非阻塞 同步和异步说的是服务端消息的通知机制,阻塞和非阻塞说的是客户端线程的状态。已客户端一次网络请求为例做简单说明: 同步同步是指一次请求没有得到结果之前就不返回。 异步请求不会...

    yeooo 评论0 收藏0
  • 关于Java IO与NIO知识都在这里

    摘要:从通道进行数据写入创建一个缓冲区,填充数据,并要求通道写入数据。三之通道主要内容通道介绍通常来说中的所有都是从通道开始的。从中选择选择器维护注册过的通道的集合,并且这种注册关系都被封装在当中停止选择的方法方法和方法。 由于内容比较多,我下面放的一部分是我更新在我的微信公众号上的链接,微信排版比较好看,更加利于阅读。每一篇文章下面我都把文章的主要内容给列出来了,便于大家学习与回顾。 Ja...

    Riddler 评论0 收藏0
  • 少啰嗦!一分钟带你读懂Java的NIO和经典IO的区别

    摘要:的选择器允许单个线程监视多个输入通道。一旦执行的线程已经超过读取代码中的某个数据片段,该线程就不会在数据中向后移动通常不会。 1、引言 很多初涉网络编程的程序员,在研究Java NIO(即异步IO)和经典IO(也就是常说的阻塞式IO)的API时,很快就会发现一个问题:我什么时候应该使用经典IO,什么时候应该使用NIO? 在本文中,将尝试用简明扼要的文字,阐明Java NIO和经典IO之...

    Meils 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<