前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >抛砖引玉NIO

抛砖引玉NIO

作者头像
三哥
发布2020-01-17 10:53:41
3800
发布2020-01-17 10:53:41
举报
文章被收录于专栏:java工会java工会

NIO

◆ ◆ ◆ ◆

在软件系统中,由于I/O的速度远比内存速度慢,所以I/O很容易成为系统的瓶颈。New I/O的简称,与旧式基于流的I/O相对。拥有如下特性:

  1. 为所有的原始类型提供Buffer缓存支持
  2. 使用Java.nio.charset.Charset作为字符集编码解码解决方案
  3. 增加通道Channel对象,作为新的原始I/O抽象
  4. 支持锁和内存映射文件的文件访问接口
  5. 提供了基于Selector的异步网络I/O
  6. 以(Block)块为基本单位处理数据

最为重要的两个组件是缓冲Buffer和通道Channel。缓冲是一块连续的内存,是NIO读写数据的中转地。通道表示缓冲数据的源头或者目的地,用于向缓冲读取或者写入数据,是访问缓冲的接口,关系如图

Channel是一个双向通道,既可读,又可写。类似于Stream,但是Stream是单向的。应用程序不能直接对Channel进行读写操作,必须通过Buffer。比如在读一个Channel的时候,需要将数据读到相应的Buffer,然后从Buffer中读取。比如在读文件时,首先将文件打开,取得文件的Channel

下面用一个文件复制的例子展示读取文件和写入文件的操作

Buffer的基本原理

◆ ◆ ◆ ◆

Buffer有三个重要参数,分别如下

写模式:

  1. position位置:当前缓冲区的位置,将从position的下一个位置写数据
  2. capactiy容量:缓冲区的总容量上限
  3. limit上限:缓冲区的实际上限,他总是小于或者等于容量。

读模式:

  1. position位置:当前缓冲区读取的位置,将从此位置后,读取数据
  2. capactiy容量:缓冲区的总容量上限
  3. limit上限:代表可读取的总容量,和上写写入的数据量相等

举个Buffer的例子

首先分配15个字节的缓冲,p=0,c=15,l=15,如下图

接着Buffer中被放入了10个byte,因此p向前移动,因为p位置始终指向下一个即将输入的位置,所以p=10,c和l不变,如下图

接着执行flip()操作。该操作会重置p。通常,将Buffer从写模式转换为读模式时需要执行此方法。flip()操作不仅重置了当前的p=0,还将limit设置到p的位置,这样做是防止在读模式中,读到应用程序根本没有操作的区域,此时如下图

接着执行5次读操作,和写操作一样,读操作也会设置p到当前位置,如下图

最后执行flip(),p归零,limit设置到position的位置,如下图

Buffer的相关操作

◆ ◆ ◆ ◆

1.Buffer的创建:有两种方式:

(1)使用静态方法allocate()从堆中分配缓冲区

(2)从一个既有数组中创建缓冲区

2.重置和清空缓冲区

(1)rewind():将position置零,并清楚标志位mark,他的作用在于提取Buffer的有效数据做准备

(2)clear():将position置零,同时将limit设置为capacity的大小,并清除了标志mask。由于清除了limit,就无法得知Buffer内哪些数据是真实有效的,该方法用于为重新写Buffer做准备

(3)flip():先将limit设置到position的位置,然后将position置零,并清除标志位mark,用在读写转换时使用

3.读/写缓冲区:比如get(),put()等方法

4.标志缓冲区:标志mark缓冲区是一项在数据处理时很有用的功能,他就像书签一样,在数据处理过程中,可以随时记录当前位置。在任意时刻,回到这个位置,从而加快和简化数据处理流程。主要方法为:

mark():记录当前位置

reset():恢复到mark所在的位置

5.复制缓冲区:以原缓冲区为基础,生成一个完全一样的新缓冲区,用duplicate()。这个函数对处理复杂的Buffer数据很好用,因为新生成的缓冲区和原缓冲共享相同的内存数据,并且一方的数据改动都相互可见,但两者又独立维护了各自的position,limit,mark,增加了灵活性。

6.缓冲分片:slice();将现有缓冲区中,创建新的子缓冲区,子缓冲区和父缓冲区共享数据。这个方法有助于将系统模块化。当需要处理一个Buffer的一个片段时,可以使用slice()方法获得一个子缓冲区,将后就像处理普通缓冲区一样处理,无需考虑缓冲区的边界问题。

7.只读缓冲区:用asReadOnlyBuffer()方法得到一个当前缓冲区一致的,并且共享内存数据的只读缓冲区。只读缓冲区对于数据安全非常有用。当缓冲区作为参数传递给对象的某个方法时,由于无法确定该方法是否破坏缓冲区的数据,此时,使用只读缓冲区可以保证数据不被修改。同时,因为只读缓冲区和原始缓冲区是共享内存块的,因此对原始缓冲区修改,只读缓冲区可见。

8.文件映射到内存:使用FileChannel.map()

9.处理结构化数据:称为散射(Scattering)和聚集(Gathering)。散射是指将数据读入一组Buffer中,而不仅仅是一个。聚集相反,是指将数据写入一组Buffer中。主要通过ScatteringByteChannel和GatheringByteChannel接口提供操作。

- end -

祝各位人人都能涨20K!

每个人都是技术大牛!

点击关注,不要走开哟~

- TEN END -

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-01-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 java工会 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档