1.java.io  最为核心的概念是流(stream),面向流的编程,要么输入流要么输出流,二者不可兼具;

2.java.nio 中拥有3个核心概念:

    Selector Channel, Buffer ,在java nio 中我们面向的是块(block)或是缓冲区(buffer) 编程 ;Buffer 本身就是一块内存,底层实现上,是个数组,

    数据的读写都是通过Buffer 来实现的,flip 进行状态的翻转,读写切换;

java 的种原生数据类型中都有各自对应的Buffer  如:IntBuffer LongBuffer  ByteBuffer CharBuffer 等,没有boolean

Channel  是指可以向其写入数据或者是从中读取数据的对象,类似 io stream,所有数据读写是通过BUFFER  执行的,永远不会出现直接向Channel 写入数据的情况以及直接向channel 读取数据的情况;channel 是双向的,可以进行读写的操作;可以更好反映底层操作情况

3. 关于NIO  Buffer 中3个重要状态属性含义:position:  limit: capacity:

  

Buffer 源码解读:

   A container for data of a specific primitive type.  Buffer 是一个具体的原始类型(除去boolean)的数据容器

    

   A buffer is a linear, finite sequence of elements of a specific primitive type. Aside from its content, the essential properties of a  buffer are its capacity, limit, and position:

   buffer 是一个 线性的,限定的,序列元素的 具体原始类型,除了他的内容之外, 一个buffer 必不可少的特性就是 capacity(容量)。limit    .position这三部分

   A buffer's <i>capacity</i> is the number of elements it contains.
   The capacity of a buffer is never negative and never changes.   capacity 是 buffer 容器里元素的个数, 它从来不会是负数,也不会被改变,在我们初始化的时候就会被我们自己定义它的大小   

    A buffer's <i>position</i> is the index of the next element to be
    * read or written. A buffer's position is never negative and is never
    * greater than its limit.

    position(位置) 是 读写下一元素的索引,position 也是从来不会是负数,从来不会大于limit

  

  

    

    <p> A buffer's <i>limit</i> is the index of the first element that should
    * not be read or written. A buffer's limit is never negative and is never
    * greater than its capacity. </p>

    limit(限定) 是不应该被读到或者被写到的元素的首位置, 它不会是负数,不会超过 capacity

 

经过以上源码解读,可以看出 capacity 在读写过程中是个不变的值,在定义的时候就固定了。

position 是随着channel 读写变换的

limit 是一个限定,用来告诉 position 应该只能写的这里,只能读到这里

比较就是 position < =limit <= capacity

即:

参数

写模式

读模式

position

当前写入的单位数据数量。

当前读取的单位数据位置。

limit

代表最多能写多少单位数据和容量是一样的。

代表最多能读多少单位数据,和之前写入的单位数据量一致。

capacity

buffer 容量

buffer 容量

<p> There is one subclass of this class for each non-boolean primitive type.
  每一个非布尔的原始类型在这个class 里都会有一个子类

<p> Transferring data

Each subclass of this class defines two categories of <i>get</i> and
* <i>put</i> operations: </p>

数据的传输 ,每一个子类都会定义 get 和put 两种方式操作

*<p> <i>Relative</i> operations read or write one or more elements starting
* at the current position and then increment the position by the number of
* elements transferred. If the requested transfer exceeds the limit then a
* relative <i>get</i> operation throws a {@link BufferUnderflowException}
* and a relative <i>put</i> operation throws a {@link
* BufferOverflowException}; in either case, no data is transferred. </p>

相对的 操作读和写一个或者多个元素在目前的position(位置坐标)通过传递元素的数量增加这个position 位置
如果请求超出了limit 的范围,相对的get 操作会抛出BufferUnderflowException 异常
put 方法操作会抛出BufferOverflowException 异常
无论发生何种情况,都没有数据传递

* <p> <i>Absolute</i> operations take an explicit element index and do not
* affect the position. Absolute <i>get</i> and <i>put</i> operations throw
* an {@link IndexOutOfBoundsException} if the index argument exceeds the
* limit. </p>

绝对的操作 进行明确一个元素的索引,不会影响postion 位置,如果索引参数超出了limit 就会抛出 IndexOutOfBoundsException 异常


标记与重置的概念

* <h2> Marking and resetting </h2>
*
* <p> A buffer's <i>mark</i> is the index to which its position will be reset
* when the {@link #reset reset} method is invoked. The mark is not always
* defined, but when it is defined it is never negative and is never greater
* than the position. If the mark is defined then it is discarded when the
* position or the limit is adjusted to a value smaller than the mark. If the
* mark is not defined then invoking the {@link #reset reset} method causes an
* {@link InvalidMarkException} to be thrown. 标记与重置 buffer 的 标记是position 将会被重置的索引,当reset 方法被调用的时候。这个标记不总是被
定义的,但是当他定义的时候,他的值不应该是负数以及它不会超出position 的值,
如果标记被定义,当position 或者limit 调整成了一个比标记还小的值,那么这个标记就会被丢弃(-1)
如果标记没有被定义,但是你调用了reset 方法,将会抛出 InvalidMarkException 异常 一句话,mark 是一个标记,当调用reset 方法时候,position 位置将会是mark 的标记的索引位置

构建一个新的buffer,构建buffer 时候做了什么事情呢?

 * <p> A newly-created buffer always has a position of zero and a mark that is
* undefined. The initial limit may be zero, or it may be some other value
* that depends upon the type of the buffer and the manner in which it is
* constructed. Each element of a newly-allocated buffer is initialized
* to zero. 一个新创建的buffer 总会有一个从0开始的position 以及 未被定义的mark(-1)
初始的limit可能是0 或者是其他的值主要取决于你buffer 的类型和构造函数的方式
新分配的缓冲区每一个元素初始化为零

-------------例子详解------------

我们以IntBuffer 为例,进行构造它的Buffer 对象


IntBuffer buffer =IntBuffer.allocate(10);//分配一个容量为10的IntBuffer


我们跟踪源码点进去,第一步,可以看出它去创建了HeapIntBuffer 对象,


public static IntBuffer allocate(int capacity) {
if (capacity < 0)
throw new IllegalArgumentException();
return new HeapIntBuffer(capacity, capacity);
}


点进去 HeapIntBuffer,可以差不多看到刚开始构造时候,capacity = limit 值


HeapIntBuffer(int cap, int lim) { // package-private


super(-1, 0, lim, cap, new int[cap], 0);


}


点进去super,看到会创建出一个容量为capacity的数组,所以说buffer 底层是数组,且初始化的position 为0 ,mark 为-1(即无效)


IntBuffer(int mark, int pos, int lim, int cap, // package-private
int[] hb, int offset)
{
super(mark, pos, lim, cap);
this.hb = hb;
this.offset = offset;
}

 

常用的方法文档解释

clear 方法

 *   <li><p> {@link #clear} makes a buffer ready for a new sequence of
* channel-read or relative <i>put</i> operations: It sets the limit to the
* capacity and the position to zero. </p></li> clear 方法 使buffer 准备以一个全新的方式进行 channel -read 操作或者相对的buffer put 操作
它会将limit 值设置成buffer capacity的值,以及position 从0 开始; 如下源码方法:可以看出clear 方法执行的操作。position 置位0 limit 等于 capacity ,清除标记-1 public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
} ------例子详解------

public static void main(String[] args) {

//分配一个容量为10 IntBuffer 底层是数组
IntBuffer buffer =IntBuffer.allocate(10);
//在够着函数创建之后,就会有了capacity limit position 的 值了
System.err.println("起始capacity值==>"+buffer.capacity());
System.err.println("起始limit值==>"+buffer.limit());
System.err.println("起始position值==>"+buffer.position());

for(int i =0;i<buffer.capacity();i++) {
//遍历在每一个buffer 节点 插入随机数
buffer.put(new SecureRandom().nextInt(10));
//打印当前的 capacity limit position 的 值;
System.out.println("循环capacity值==>"+buffer.capacity());
System.out.println("循环limit值==>"+buffer.limit());
System.out.println("循环position值==>"+buffer.position());
}

//buffer clear 方法调用

buffer.clear();

System.err.println("clear 后capacity值==>"+buffer.capacity());
System.err.println("clear 后limit值==>"+buffer.limit());
System.err.println("clear 后position值==>"+buffer.position());

//......再进行自己的put 操作

}

 
flip 方法

 *   <li><p> {@link #flip} makes a buffer ready for a new sequence of
* channel-write or relative <i>get</i> operations: It sets the limit to the
* current position and then sets the position to zero. </p></li> clear 方法 使buffer 准备以一个全新的方式进行 channel -write操作或者相对的buffer get操作
他会将limit 值设置为当前position 值,将position 设置为0 如下源码方法:可以看出flip 方法执行的操作。 public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
} -------例子详解

public static void main(String[] args) {

//分配一个容量为10 IntBuffer 底层是数组
IntBuffer buffer =IntBuffer.allocate(10);
//在够着函数创建之后,就会有了capacity limit position 的 值了
System.err.println("起始capacity值==>"+buffer.capacity());
System.err.println("起始limit值==>"+buffer.limit());
System.err.println("起始position值==>"+buffer.position());

//为了看到limit 效果,这里设置循环5次
for(int i =0;i<5;i++) {
//遍历在每一个buffer 节点 插入随机数
buffer.put(new SecureRandom().nextInt(10));
//打印当前的 capacity limit position 的 值;
System.out.println("循环capacity值==>"+buffer.capacity());
System.out.println("循环limit值==>"+buffer.limit());
System.out.println("循环position值==>"+buffer.position());
}

//buffer flip 方法调用

buffer.flip();

System.err.println("flip 后capacity值==>"+buffer.capacity());
System.err.println("flip 后limit值==>"+buffer.limit());
System.err.println("flip 后position值==>"+buffer.position());

while(buffer.hasRemaining()) {//=position < limit的时候循环;

System.out.println("buffer的值===>"+buffer.get());
}

}

 
rewind(倒回) 方法;

 *   <li><p> {@link #rewind} makes a buffer ready for re-reading the data that
* it already contains: It leaves the limit unchanged and sets the position
* to zero. </p></li>
*
* </ul> rewind 方法是在已经存在的容器里重新读取数据做好准备,他会保持limit 不改变并且使position 为0 如下源码方法:可以看出rewind方法执行的操作。 public final Buffer rewind() {
position = 0;
mark = -1;
return this;
}

    public static void main(String[] args) throws Exception {

        FileInputStream file = new FileInputStream("c:\\demo.txt");
//获取channel 对象
FileChannel fileChannel=file.getChannel();
//读写操作都会用到buffer
ByteBuffer byteBuffer = ByteBuffer.allocate(5112);
//channel 读取数据到buffer
fileChannel.read(byteBuffer); //状态翻转,切换为读
byteBuffer.flip(); while(byteBuffer.hasRemaining()) { byte b =byteBuffer.get();
System.out.println((char)b);
} file.close();
}

java NIO Buffer 详解(1)的更多相关文章

  1. Java NIO Buffer详解

    一.ByteBuffer类型化的put与get方法 /** * ByteBuffer类型化的put与get方法 */ public class NioTest5 { public static voi ...

  2. Java NIO API详解

    在JDK 1.4以前,Java的IO操作集中在java.io这个包中,是基于流的同步(blocking)API.对于大多数应用来说,这样的API使用很方便,然而,一些对性能要求较高的应用,尤其是服务端 ...

  3. Java NIO API详解(转)

    原文连接: http://www.blogjava.net/19851985lili/articles/93524.html 感谢原作者 NIO API 主要集中在 java.nio 和它的 subp ...

  4. Java NIO全面详解(看这篇就够了)

    很多技术框架都使用NIO技术,学习和掌握Java NIO技术对于高性能.高并发网络的应用是非常关键的@mikechen NIO简介 NIO 中的 N 可以理解为 Non-blocking,不单纯是 N ...

  5. Java NIO 的前生今世 之四 NIO Selector 详解

    Selector Selector 允许一个单一的线程来操作多个 Channel. 如果我们的应用程序中使用了多个 Channel, 那么使用 Selector 很方便的实现这样的目的, 但是因为在一 ...

  6. Java String类详解

    Java String类详解 Java字符串类(java.lang.String)是Java中使用最多的类,也是最为特殊的一个类,很多时候,我们对它既熟悉又陌生. 类结构: public final ...

  7. JAVA IO 类库详解

    JAVA IO类库详解 一.InputStream类 1.表示字节输入流的所有类的超类,是一个抽象类. 2.类的方法 方法 参数 功能详述 InputStream 构造方法 available 如果用 ...

  8. 前端后台以及游戏中使用Google Protocol Buffer详解

    前端后台以及游戏中使用Google Protocol Buffer详解 0.什么是protoBuf protoBuf是一种灵活高效的独立于语言平台的结构化数据表示方法,与XML相比,protoBuf更 ...

  9. Thrift实现C#调用Java开发步骤详解

    概述 Thrift实现C#调用Java开发步骤详解 详细 代码下载:http://www.demodashi.com/demo/10946.html Apache Thrift 是 Facebook ...

随机推荐

  1. spring MVC初始化过程学习笔记1

    如果有错误请指正~ 1.springmvc容器和spring的关系? 1.1 spring是个容器,主要是管理bean,不需要servlet容器就可以启动,而springMVC实现了servlet规范 ...

  2. 尚硅谷springboot学习16-slf4j的使用

    如何在系统中使用SLF4j 以后开发的时候,日志记录方法的调用,不应该来直接调用日志的实现类,而是调用日志抽象层里面的方法: 给系统里面导入slf4j的jar和 logback的实现jar impor ...

  3. 尚硅谷springboot学习11-占位符

    1.随机数 2.占位符获取之前配置的值,如果没有可以使用:指定默认值

  4. 构造函数,C++内存管理,内存泄漏定位

    构造函数 1.构造顺序 虚基类构造函数,基类构造函数,类对象构造函数,自己的构造函数 2.必须使用初始化列表 (1) 引用成员,常量成员: (2) 基类没默认构造函数(自己重载覆盖了), (3)类对象 ...

  5. vue项目动态控制数据变动时箭头样式

    html代码 <div class="top_precent"> <span :class="{arrow:numPrecent<0}" ...

  6. python实现根据文件关键字进行切分为多个文件

    来源:在工作过程中,需要统计一些trace信息,也就是一些打点信息,而打点是通过关键字进行的,因此对一个很大的文件进行分析时,想把两个打点之间的内容单独拷贝出来进行分析 #!/usr/bin/env ...

  7. curl命令解析

    curl命令可以实现http post或者get的请求,是linux下的命令行工具 1.1.直接请求url,打印标准输出 1.2.使用-o参数,可以标准输出到指定的位置 [root@VM-3-10-1 ...

  8. Java编译时多态和运行时多态

    来源:https://blog.csdn.net/wendizhou/article/details/73733061 编译时多态:主要是方法的重载,通过参数列表的不同来区分不同的方法. 运行时多态: ...

  9. sass 使用clac的问题

    最后在github的issue中找到了方法,要想在sass的calc中使用变量,必须对这个变量使用sass的插值方法(#{$variable}). 所以把代码改正下面的形式就可以了: width: c ...

  10. Signed Distance Field Technique

    [Distance Field Technique] 一种小纹理高清放大的技术. A distance field is generated from a high resolution image, ...