NIO

## NIO概述 ##

Java NIO(New IO) 是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同, NIO支持面向缓冲区的、基于通道的IO操作。 NIO将以更加高效的方式进行文件的读写操作。

JDK之后的NIO:也叫做NIO2(BIO)

  Path:路径(与平台无关)

  Paths:有一个静态方法返回路径(返回Path的静态方法)

    public static Path get(URI uri);

  Files:提供静态方法(操作文件的工具类)

    public static long copy(Path source, OutputStream out)

    将文件中的所有字节复制到输出流。

    public static Path write(Path path, Iterable lines, Charset cs, OpenOption... options)

    将文本行写入文件。

## NIO与IO区别 ##

| IO |NIO|

| - |

| 面向流(Stream Oriented) | 面向缓冲区(Buffer Oriented) |

| 阻塞IO(Blocking IO) | 非阻塞IO(Non Blocking IO) |

| (无) | 选择器(Selectors) |

## 通道和缓冲区 ##

Java NIO系统的核心在于:通道(Channel)和(Buffer)。通道表示打开到 IO 设备(例如:套接字)的连接。若需要使用 NIO 系统,需用于连接 IO 设备的通道以及用于容纳数据区。然后操作缓冲区,对数据进行处理

**简而言之, Channel 负责传输, Buffer 负责存储**

### NIO缓冲区(Buffer) ###

- 缓冲区(Buffer) :一个用于特定基本数据类型的容器。由 java.nio 包定义的,所有缓冲区都是 Buffer 抽象类的子类

- Java NIO 中的 Buffer 主要用于与 NIO 通道进行交互,数据是从通道读入缓冲区,从缓冲区写入通道中的

Buffer 就像一个数组,可以保存多个相同类型的数据。根据数据类型不同(boolean 除外) ,有以下 Buffer 常用子类:

* ByteBuffer

* CharBuffer

* ShortBuffer

* IntBuffer

* LongBuffer

* FloatBuffer

* DoubleBuffer

上述 Buffer 类 他们都采用相似的方法进行管理数据,只是各自管理的数据类型不同而已。

都是通过如下方法获取一个 Buffer对象:

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

Buffer 中的重要概念:

> 容量 (capacity) : 表示 Buffer 最大数据容量,缓冲区容量不能为负,并且创

建后不能更改。

> 限制 (limit): 第一个不应该读取或写入的数据的索引,即位于 limit 后的数据

不可读写。缓冲区的限制不能为负,并且不能大于其容量。

> 位置 (position): 下一个要读取或写入的数据的索引。缓冲区的位置不能为

负,并且不能大于其限制

> 标记 (mark)与重置 (reset): 标记是一个索引,通过 Buffer 中的 mark() 方法

指定 Buffer 中一个特定的 position,之后可以通过调用 reset() 方法恢复到这

个 position

>并且  0 < mark <= position <=limit <= capacity

1. 分配一个缓冲区

要获得一个Buffer对象,你必须首先分配它,通过allocate()分配了一个10字节大小的缓冲区。

```java

ByteBuffer buf = ByteBuffer.allocate(10);

```

![allocate](image/aa.png)

2. 将数据写入缓冲区

将数据写入缓冲区有两种方式:

  1.利用 put() 存入数据到缓冲区中

```java

String str = "abcde";

buf.put(str.getBytes());

```

![allocate](image/bb.png)

  2.将数据从 Channel写入Buffer

```java

int bytesRead = inChannel.read(buf);

//读入缓冲区。

```

3. filpp()

该flip()方法将a Buffer从写入模式切换到读取模式。调用flip()将position返回设置为0,并将其设置为limit 刚才的位置。

换句话说,position现在标记了读取位置,并limit标记了多少字节,字符等被写入缓冲区 - 可以读取的字节数,字节数等限制。

```java

buf.flip();

```

4. 从缓冲区读取数据

有两种方法可以从Buffer中读取数据。

1.将数据从缓冲区读入通道。

```java

//从缓冲区读入通道。

int bytesWritten = inChannel.write(buf);

```

2.使用其中一个get()方法自己从缓冲区中读取数据。

```java

byte[] dst = new byte[buf.limit()];

buf.get(dst);

System.out.println(new String(dst, 0, dst.length));

```

```java

```

5. rewind()

Buffer.rewind() 让 position 返回到0,这样你就可以重新读取缓冲区中的所有数据。在limit保持不变,因此仍然标记多少个元素(字节,字符等),可以从被读取Buffer。

6. clear()和compact()

一旦你完成了读取数据,Buffer 准备好再次写入。你可以通过调用clear()或调用compact()。

如果调用clear(),则position将设置回0并且limit会变成capacity。, 换句话说,缓冲区被清除,但是缓冲区中的数据未被清除。, 只有markers告诉您可以将数据写入缓冲区的位置。

如果在调用clear()时缓冲区中存在未读取的数据,那么数据将处于“forgotten”,这意味着不再有任何标记,指示已读取的数据以及尚未读取的数据。

如果Buffer中仍有未读数据,并且想稍后read,需要先写一些内容,调用compact()而不是clear()。

compact()将所有未读数据复制到缓冲区的开始处。, 然后它将position设置在最后一个未读元素之后。, 极限属性仍然设置为容量,就像clear()一样。, 现在缓冲区已准备好写入,但不会覆盖未读数据。

7. mark()和reset()

可以通过调用Buffer.mark()方法在Buffer中标记给定的位置。然后可以通过调用该Buffer.reset() 方法将位置重新设置回标记的位置。

```java

        String str = "abcde";

ByteBuffer buf = ByteBuffer.allocate(1024);

buf.put(str.getBytes());

buf.flip();

byte[] dst = new byte[buf.limit()];

buf.get(dst, 0, 2);

System.out.println(new String(dst, 0, 2));

System.out.println(buf.position());

//mark() : 标记

buf.mark();

buf.get(dst, 2, 2);

System.out.println(new String(dst, 2, 2));

System.out.println(buf.position());

//reset() : 恢复到 mark 的位置

buf.reset();

System.out.println(buf.position());

```

8. equals()和compareTo()

可以使用equals()和compareTo()来比较两个缓冲区

equals()

它们是相同的类型(byte,char,int等)

它们在缓冲区中具有相同数量的剩余字节,字符等。

所有剩余的字节,字符等是相等的。

正如你所看到的,equals只比较缓冲区的一部分,而不是它内部的每一个元素。, 实际上,它只是比较缓冲区中的其余元素。

compareTo()

该compareTo()方法比较两个缓冲区的其余元素(字节,字符等),用于例如排序例程。在下列情况下,缓冲区被认为比另一个缓冲区“小”

第一个元素等于另一个缓冲区中的对应元素,小于另一个缓冲区中的元素。

所有的元素都是相等的,但第一个缓冲区在第二个缓冲区之前耗尽元素(元素较少)。

### NIO通道(Channel) ###

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容