IO 

是主存和外部设备 ( 硬盘、终端和网络等 ) 拷贝数据的过程。 IO 是操作系统的底层功能实现,底层通过 I/O 指令进行完成。

Java标准io回顾

在Java1.4之前的I/O系统中,提供的都是面向流的I/O系统。 InputStream\OutputStream( 字节流 ) :一次传送一个字节。 Reader\Writer( 字符流 ) :一次一个字符。

NIO

nio 是java nonblocking(非阻塞) IO 的简称(还有种解释是 New IO),在jdk1.4 里提供的新API。Sun 官方标榜的特性如下: 为所有的原始类型提供(Buffer)缓存支持。字符集编码解码解决方案。 Channel :一个新的原始I/O 抽象。支持锁和内存映射文件的文件访问接口。 提供多路(non-bloking) 非阻塞式的高伸缩性网络I/O 。

在NIO中有几个核心对象需要掌握:缓冲区(Buffer)、通道(Channel)、选择器(Selector)。

Buffer

缓冲区实际上是一个容器对象,更直接的说,其实就是一个数组,在NIO库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的; 在写入数据时,它也是写入到缓冲区中的。

一个 buffer 主要由 position,limit,capacity 三个变量来控制读写的过程。

position:指定了下一个将要被写入或者读取的元素位置。

limit:指定还有多少数据需要取出,或者还有多少空间可以放入数据,是最后的位置,不是大小。

capacity:指定了可以存储在缓冲区中的最大数据容量,实际上,它指定了底层数组的大小。

三者的关系:0 <= position <= limit <= capacity 。 初始的时候limit ==capacity。

Buffer 常见方法:

flip(): 重设此缓冲区,将limit设置为当前position,然后将当前position设置为0 。读写缓冲区都会改变position和limit的位置。

clear(): 置为初始化状态 (position 变成 0 , limit 变成 capacity) 。

asReadOnlyBuffer():返回一个只读的缓冲区,和原始缓冲区共用同一块内存,只是只读。修改会抛异常。不能将只读的缓冲区转换为可写的缓冲区。

get():返回当前位置的数据,同时将 position+=1。

put():加入元素,position+=增加的元素个数。

remaining():返回剩余的数据的数量, (即limit - position)。

hasRemaining():是否还有剩余数据,循环的时候用。

rewind(): 将 position 重置为 0 ,一般用于重复读。

limit(int newLimit),position(int newPosition):修改这两个值。

compact(): 将未读取的数据拷贝到 buffer 的头部位。

mark()、reset(): mark 可以标记一个位置, reset 可以重置到该位置。

每个非布尔基本类型都有一个缓冲区类。Buffer 常见类型: ByteBuffer 、 MappedByteBuffer 、 CharBuffer 、 DoubleBuffer 、 FloatBuffer 、 IntBuffer 、 LongBuffer 、 ShortBuffer 。

//创建Buffer:
ByteBuffer bf = ByteBuffer.allocate(1024);
ByteBuffer bfd = ByteBuffer.allocateDirect(1024); // ByteBuffer 才有这个方法 //使用字节数组创建ByteBuffer
byte[] bytes = new byte[10];
ByteBuffer buffer = ByteBuffer.wrap(bytes); //使用ByteBuffer存储字符串
ByteBuffer buffer = ByteBuffer.allocate(100);
CharBuffer cBuffer = buffer.asCharBuffer();
cBuffer.put("Hello World");
cBuffer.flip();
String result = cBuffer.toString();

注意:ByteBuffer转成CharBuffer后,缓冲区总的字节数还是100,但是CharBuffer加入的每个字符都是占用2个字节,所以它的capacity变成了 100/2=50;put("Hello World")中每个字符都是2个字节的。 另,对CharBuffer的操作不会影响ByteBuffer的position、limit等字段的值。

Channel:

可以通过它读取和写入数据。拿 NIO 与原来的 I/O 做个比较,通道就像是Stream,而且是面向缓冲区的。所有数据都通过 Buffer 对象来处理。不会将字节直接写入通道中,相反,是将数据写入包含一个或者多个字节的缓冲区。同样,不会直接从通道中读取字节,而是将数据从通道读入缓冲区,再从缓冲区获取这个字节。

通道与流的不同之处在于通道是双向的(但是某一个channel可能只支持读或写)。而流只是在一个方向上移动(一个流必须是 InputStream 或者 OutputStream 的子类), 而 通道 可以用于读、写或者同时用于读写。因为它们是双向的,所以通道可以比流更好地反映底层操作系统的真实情况。特别是在 UNIX 模型中,底层操作系统通道是双向的。

//Channel直接可以用下面两个方法直接传递数据:
long transferFrom(ReadableByteChannel src, long position, long count)
long transferTo(long position, long count, WritableByteChannel target)
//文件拷贝的例子
FileInputStream fin = new FileInputStream("D:/work/test.txt");
FileOutputStream fout = new FileOutputStream("D:/work/output.txt");
FileChannel inChannel = fin.getChannel();
FileChannel outChannel = fout.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
while(true){
  int ret = inChannel.read(buffer);
  if( ret == -1)
    break;
  buffer.flip(); //该方法为父类Buffer的方法
  outChannel.write(buffer);
  buffer.clear(); //该方法为父类Buffer的方法
}

往Channel中写入数据:

int write(ByteBuffer src); // 从buffer当前position开始读取数据,写入到channel。position+=实际读取写出的数据大小,limit不变。write返回实际写入的数据量。

基于write的机制,有这种写法:

while(buf.hasRemaining()) { 
    channel.write(buf);
}

nio.charset

字符编码解码 : 字节本身只是一些数字,放到正确的上下文中被正确的解析。向 ByteBuffer 中存放数据时需要考虑字符集的编码方式,读取展示 ByteBuffer 数据时涉及对字符集解码。

Java.nio.charset 提供了编码解码一套解决方案。

Charset charset = Charset.forName("GBK");// 创建GBK字符集
ByteBuffer bf = charset.encode("hello world我是中国人");
CharBuffer cf = charset.decode(bf); // 每调用一次都会创建一个CharsetDecoder 对象 String name = charset.displayName();
String ret = cf.toString(); CharsetDecoder decoder = ch.newDecoder();
CharsetEncoder encoder = ch.newEncoder();

直接缓冲区

是为加快I/O速度,使用一种特殊方式为其分配内存的缓冲区,JDK文档中的描述为:给定一个直接字节缓冲区,Java虚拟机将尽最大努 力直接对它执行本机I/O操作。也就是说,它会在每一次调用底层操作系统的本机I/O操作之前(或之后),尝试避免将缓冲区的内容拷贝到一个中间缓冲区中 或者从一个中间缓冲区中拷贝数据。

要分配直接缓冲区,需要调用allocateDirect()方法,而不是allocate()方法,使用方式与普通缓冲区并无区别。还可以用内存映射文件创建直接缓冲区。

分散和聚集

分散/聚集 I/O 是使用多个而不是单个缓冲区来保存数据的读写方法。

一个分散的读取就像一个常规通道读取,只不过它是将数据读到一个缓冲区数组中而不是读到单个缓冲区中。同样地,一个聚集写入是向缓冲区数组而不是向单个缓冲区写入数据。

分散/聚集 I/O 对于将数据流划分为单独的部分很有用,这有助于实现复杂的数据格式。

ScatteringByteChannel、GatheringByteChannel 是两个interface,而 FileChannel 和 SocketChannel 等实现了这两个接口。

ScatteringByteChannel 是一个具有两个附加读方法的通道:

long read( ByteBuffer[] dsts );
long read( ByteBuffer[] dsts, int offset, int length );

这些 long read() 方法很像标准的 read 方法,只不过它们不是取单个缓冲区而是取一个缓冲区数组。

在 分散读取 中,通道依次填充每个缓冲区。填满一个缓冲区后,它就开始填充下一个,在移动下一个buffer前,必须填满当前的buffer,这也意味着它不适用于动态消息(译者注:消息大小不固定)。在某种意义上,缓冲区数组就像一个大缓冲区。

GatheringByteChannel聚集写入 类似于分散读取,只不过是用来写入。它也有接受缓冲区数组的方法:

long write( ByteBuffer[] srcs );
long write( ByteBuffer[] srcs, int offset, int length );

分散/聚集的应用

分散/聚集 I/O 对于将数据划分为几个部分很有用。例如,您可能在编写一个使用消息对象的网络应用程序,每一个消息被划分为固定长度的头部和固定长度的正文。您可以创建一个刚好可以容纳头部的缓冲区和另一个刚好可以容难正文的缓冲区。当您将它们放入一个数组中并使用分散读取来向它们读入消息时,头部和正文将整齐地划分到这两个缓冲区中。我们从缓冲区所得到的方便性对于缓冲区数组同样有效。因为每一个缓冲区都跟踪自己还可以接受多少数据,所以分散读取会自动找到有空间接受数据的第一个缓冲区。在这个缓冲区填满后,它就会移动到下一个缓冲区。聚集写对于把一组单独的缓冲区中组成单个数据流很有用。为了与上面的消息例子保持一致,您可以使用聚集写入来自动将网络消息的各个部分组装为单个数据流,以便跨越网络传输消息。

文件锁

文件大小

RandomAccessFile只能打开文件,不能是文件夹,否则会抛异常

RandomAccessFile rFile = new RandomAccessFile("/sdcard/update.zip", "rw");
FileChannel fChannel = rFile.getChannel();
File file = new File("/sdcard/update.zip"); long chaneelSize = fChannel.size();
long rSize = rFile.length();
long fSize = file.length();
//得到的三个大小值是一样的

Pipe管道

Java nio 管道是2个线程之间的单向数据连接。Pipe有一个source通道和一个sink通道。数据会被写到sink通道,从source通道读取。

//创建管道
Pipe pipe = Pipe.open(); //写数据到管道,需要访问sink通道
Pipe.SinkChannel sinkChannel = pipe.sink();
sinkChannel.write(buf); //从读取管道的数据,需要访问source通道
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);

JAVA NIO简介-- Buffer、Channel、Charset 、直接缓冲区、分散和聚集、文件锁的更多相关文章

  1. Java NIO之Buffer(缓冲区)

    ​ Java NIO中的缓存区(Buffer)用于和通道(Channel)进行交互.数据是从通道读入缓冲区,从缓冲区写入到通道中的. ​ 缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存.这 ...

  2. java NIO简介

    1)java nio简介 nio 是 java New IO 的简称,在 jdk1.4 里提供的新 api . Sun 官方标榜的特性如有:为所有的原始类型提供 (Buffer) 缓存支持:字符集编码 ...

  3. Java NIO系列教程(一)java NIO简介

    这个系列的文章,我们开始玩一玩IO方面的知识,对于IO和NIO,我们经常会接触到,了解他们的基本内容,对于我们的工作会有特别大的帮助.这篇博文我们仅仅是介绍IO和NIO的基本概念,以及一些关键词. 基 ...

  4. JAVA NIO 简介 (netty源码死磕1.1)

    [基础篇]netty 源码死磕1.1:  JAVA NIO简介 1. JAVA NIO简介 Java 中 New I/O类库 是由 Java 1.4 引进的异步 IO.由于之前老的I/O类库是阻塞I/ ...

  5. 5. 彤哥说netty系列之Java NIO核心组件之Channel

    你好,我是彤哥,本篇是netty系列的第五篇. 简介 上一章我们一起学习了如何使用Java原生NIO实现群聊系统,这章我们一起来看看Java NIO的核心组件之一--Channel. 思维转变 首先, ...

  6. (一:NIO系列)JAVA NIO 简介

    出处:JAVA NIO 简介 Java 中 New I/O类库 是由 Java 1.4 引进的异步 IO.由于之前老的I/O类库是阻塞I/O,New I/O类库的目标就是要让Java支持非阻塞I/O, ...

  7. Java NIO 之 Buffer

    Java NIO 之 Buffer Java NIO (Non Blocking IO 或者 New IO)是一种非阻塞IO的实现.NIO通过Channel.Buffer.Selector几个组件的协 ...

  8. JAVA基础知识之NIO——Buffer.Channel,Charset,Channel文件锁

    NIO机制 NIO即NEW IO的意思,是JDK1.4提供的针对旧IO体系进行改进之后的IO,新增了许多新类,放在java.nio包下,并对java.io下许多类进行了修改,以便使用与nio. 在ja ...

  9. Java NIO:Buffer、Channel 和 Selector

    Buffer 一个 Buffer 本质上是内存中的一块,我们可以将数据写入这块内存,之后从这块内存获取数据. java.nio 定义了以下几个 Buffer 的实现,这个图读者应该也在不少地方见过了吧 ...

随机推荐

  1. Drools环境搭建(转)

    Eclipse3.5安装Drools5.2.0.Final插件 到Drools下载页面(现在是http://www.jboss.org/drools/downloads.html) -下载并解压Dro ...

  2. C#中MessageBox用法大全

    我们在程序中经常会用到MessageBox. MessageBox.Show()共有21中重载方法.现将其常见用法总结如下: 1.MessageBox.Show("Hello~~~~&quo ...

  3. iOS按钮设置图片在上文字在下

    UIButton同时设置Title和Image后,默认是图片在左文字在右,如下图1,很多情况下我们希望图片在上图片在下,如下图2,只需要简单的几行代码,即可实现. (1)因为需要处理多个按钮,所以将实 ...

  4. wamp出现You don’t have permission to access/on this server提示的解决方法

    本地搭建wamp 输入http://127.0.0.1访问正常,当输入http://localhost/ apache出现You don't have permission to access/on ...

  5. 十个最适合 Web 和 APP 开发的 NodeJS 框架

    在浏览器以外运行 JavaScript 对于 JavaScript 爱好者来说非常神奇,同时也肯定是 web 应用程序开发界最受欢迎的进步之一.全球各地的开发者张开双臂拥抱 NodeJS. 对于新手来 ...

  6. 使用RelativeLayout控制WebView以及Bottom按钮的位置

    使用RelativeLayout控制WebView以及Bottom按钮的位置 (地址) 在Design View中加入控件RelativeLayout, WebView, LinearLayout(H ...

  7. Discuz 7.0版块横排显示版块图标和版块简介的方法

    Discuz 7.0版块横排显示版块图标和版块简介的方法 最近很多朋友咨询Discuz论坛设置论坛版块横排后,如何设置显示版块图标和简介的问题. 一.显示板块图标 找到templates\defaul ...

  8. 【转】Qt下使用glut库

    ps:这个说的很明白,尤其是win10环境下用mingw环境时编程时碰到的问题, 1.加 windows.h 2.在.pro 添加libs     博文地址:Qt下使用glut库   本人使用的环境 ...

  9. 分布式系统(Distributed System)资料

    这个资料关于分布式系统资料,作者写的太好了.拿过来以备用 网址:https://github.com/ty4z2008/Qix/blob/master/ds.md 希望转载的朋友,你可以不用联系我.但 ...

  10. 腾讯优测优分享 | Android适配中的一些特殊情况小结

    腾讯优测是专业的自动化测试平台,提供全面兼容适配测试,远程真机租用等多维度的测试服务! 作为一名"艰苦卓绝"的软件工程师,我在开发路上经常被各种奇葩情况虐的体无完肤...今天就想与 ...