简介

NIO的所有类都被放在java.nio包或其子包下。

特点

  1. 面向块的I/O:传统JavaIO是面向流的I/O。流I/O一次处理一个字节。NIO中引入了缓冲区(Buffer)的概念,缓冲区作为传输数据的基本单位块,所有对数据的操作都是基于将数据移进/移出缓冲区而来。
  2. 非阻塞的I/O + 就绪性选择:非阻塞I/O则允许线程在有数据的时候处理数据,没有数据的时候干点别的,提高了资源利用率。就绪性选择通常是建立在非阻塞的基础上,并且更进一步,它把检查哪些I/O请求的数据准备好这个任务交给了底层操作系统,操作系统会去查看并返回结果集合,这样我们只需要关心那些准备好进行操作的IO通道。
  3. 文件锁定和内存映射文件等操作系统特性:内存映射利用虚拟内存技术提供对文件的高速缓存,使读取磁盘文件就像从内存中读取一样高效,但是却不会有内存泄漏的危险,因为在内存中不会存在文件的完整拷贝。

Buffer

简介

Buffer有Byte、Short、Int、Long、Float、DoubleBuffer六个类别,起缓存作用。
Buffer有四个基本属性:
  1、capacity 容量,buffer能够容纳的最大元素数目,在Buffer创建时设定并不能更改
  2、limit buffer中有效位置数目,不能对超过limit中的区域进行读写。
  3、position 下一个读或者写的位置
  4、mark 用于记忆的标志位,配合reset()使用,初始值未设定,调用mark后将当前position设为值
图片描述

利用Buffer读写数据,通常遵循四个步骤:

获取buffer
把数据写入buffer;
调用flip;
从Buffer中读取数据;
调用buffer.clear()或者buffer.compact()

方法:

获取:
static xxxBuffer allocate(int capacity)//创建容量为capacity的buffer
写入:
void  putxxx(xxx f)
void  putxxx(int index, xxx f)

void flip()//limit=position,position=0 //方便读取数据

读取:
xxx  getFloat()
xxx  getFloat(int index)

void clear()//position=0,limit=capacity,方便再次装入数据

其他方法:
int capacity()//获取capacity
boolean hasRemaining()//是否有元素未处理,即position<limit
int limit()
int position()
int remainint()//return limit-position

Channel

Channel用于在字节缓冲区和位于通道另一侧的实体(通常是一个文件或套接字)之间有效地传输数据。。与缓冲区不同,通道API主要由接口指定。不同的操作系统上通道实现(Channel Implementation)会有根本性的差异,所以通道API仅仅描述了可以做什么。因此很自然地,通道实现经常使用操作系统的本地代码。通道接口允许您以一种受控且可移植的方式来访问底层的I/O服务。

Channel和流的区别

  1. Channel可以将整个文件或文件的一部分映射成为buffer
  2. Channel是一个对象,可以通过它读取和写入数据。拿 NIO 与原来的 I/O 做个比较,通道就像是流。所有数据都通过 Buffer 对象来处理。您永远不会将字节直接写入通道中,相反,您是将数据写入包含一个或者多个字节的缓冲区。同样,您不会直接从通道中读取字节,而是将数据从通道读入缓冲区,再从缓冲区获取这个字节。
  3. 既可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的。
  4. 通道可以异步地读写。
  5. 通道中的数据总是要先读到一个 Buffer,或者总是要从一个 Buffer 中写入。
  6. FileChannel对象是线程安全(thread-safe)的。

常用的Channel

FileChannel:从文件中读写数据。
DatagramChannel:能通过UDP读写网络中的数据。
SocketChannel:能通过TCP读写网络中的数据。
ServerSocketChannel:可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。

使用

  1. 所有Channel都应该使用传统的流来构建,如:FileChannel channel=fileInputStream.getChannel().
    RandomAccessFile也有这个方法,Channel是可读还是可写,取决于它的打开方式r/rw
  2. Channel常用方法:
将文件映射到内存
ByteBuffer buffer=channel.map(FileChannel.MapMode.READ_ONLY,0,file.length);

写到Channel
channel.write(buffer)

读取到buffer
channel.read(byteBuffer)

移动Channel的positon
channel.position(long length)

字符集和Charset

JAVA默认使用Unicode编码,但是有些操作系统不适用Unicode。

方法

获取支持的所有字符集
SortedMap<String,Charset>=Charset.availableCharsets()

获取charset实例
charset=Charset.forName("gbk")

编解码
charbuffer=charset.decode(bytebuffer)
bytebuffer=charset.encoce(charbuffer/string)

文件锁(进程级)

FileLock支持文件锁定功能。在FileChannel中提供lock和tryLock方法来获得FileLock对象。
fileLock可以只锁定文件的一部分。

lock(long position , long size,boolean shared)//阻塞式
tryLock(long position ,long sized,boolean shared)//非阻塞

FileLock lock=fileChannel.tryLock();
dosomething.....
lock.release();

文件锁是JVM持有的,如果两个进程运行在同一个JVM,则他们不能对同一个文件加锁。

Java NIO学习笔记---Channel


曾纪文
201 声望22 粉丝

« 上一篇
JAVA IO
下一篇 »
JAVA NIO.2