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. BlockingQueue之DelayQueue的学习使用

    DelayQueue 是一中阻塞队列,需要实现接口Delayed定义的方法.做下使用记录和心得吧, @Datapublic class DelayQueueExample implements Del ...

  2. compose配置文件参数详解

    转自:https://www.cnblogs.com/jsonhc/p/7814138.html 本文介绍compose配置文件参数的使用,熟练编写compose文件 [root@docker lnm ...

  3. Go语言学习笔记(1)

    包 package 声明包,import 导入包,导入的包名要用"",包中导出的名字以大写字母打头. package main import "fmt" imp ...

  4. [PHP]PHP自定义遍历目录下所有文件的方法

    header('content-type:text/html;charset=utf-8');/** *   方法一:使用readir()遍历目录 */function listDir($dir){  ...

  5. 关于WSSE验证-- 一种验证用户的方法

    大家通常验证用户做法: 1. BASIC验证模式: 把用户名和密码采用Base64编码之后,放在HTTP HEADER里,发到服务器的. 2. FORM验证模式: 就什么都不处理,直接发到服务器. 3 ...

  6. ArcGIS案例学习笔记-批处理擦除挖空挖除相减

    ArcGIS案例学习笔记-批处理擦除挖空挖除相减 联系方式:谢老师,135-4855-4328,xiexiaokui#qq.com 目的:批处理擦除.挖空.挖除.相减 数据源:chp13/ex5/pa ...

  7. List,Set,Map集合的遍历方法

    List的三种实现:ArrayList(数组)  LinkedList(链表)  Vector(线程安全) List集合遍历方法: List<String> list = new Arra ...

  8. tensorflow中run和eval的区别(转)

    在tensorflow中,eval和run都是获取当前结点的值的一种方式. 在使用eval时,若有一个 t 是Tensor对象,调用t.eval()相当于调用sess.run(t) 一下两段代码等效: ...

  9. tensorflow 之tensorboard 对比不同超参数训练结果

    我们通常使用tensorboard 统计我们的accurate ,loss等,并绘制曲线,通常是使用一次训练中的, 但是,机器学习中通常要对比不同的 ‘超参数’给模型训练和预测能力的不同这时候如何整合 ...

  10. Oracle11g服务详细介绍

    Oracle11g服务详细介绍及哪些服务是必须开启的? Oracle ORCL VSS Writer Service Oracle卷映射拷贝写入服务,VSS(Volume Shadow Copy Se ...