Java NIO(转自:http://www.iteye.com/magazines/132-Java-NIO#585)

Java NIO提供了与标准IO不同的IO工作方式:

    • Channels,Buffers
    • Asynchronous IO
    • Selectors

Buffer的基本用法

使用Buffer读写数据一般遵循以下四个步骤:

    • 分配内存:ByteBuffer buf = ByteBuffer.allocate(48);

    • 写入数据到Buffer:int bytesRead = inChannel.read(buf); //从Channel写到Buffer

    • 调用flip()方法:flip方法将Buffer从写模式切换到读模式。调用flip()方法会将position设回0,并将limit设置成之前position的值。

    • 从Buffer中读取数据:int bytesWritten = inChannel.write(buf);  //从Buffer读取数据到Channel  byte aByte = buf.get();//使用get()方法从Buffer中读取数据

    • 调用clear()方法或者compact()方法:一旦读完Buffer中的数据,需要让Buffer准备好再次被写入。可以通过clear()或compact()方法来完成。

当向buffer写入数据时,buffer会记录下写了多少数据。一旦要读取数据,需要通过flip()方法将Buffer从写模式切换到读模式。在读模式下,可以读取之前写入到buffer的所有数据。

一旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入。有两种方式能清空缓冲区:调用clear()或compact()方法。clear()方法会清空整个缓冲区。compact()方法只会清除已经读过的数据。任何未读的数据都被移到缓冲区的起始处,新写入的数据将放到缓冲区未读数据的后面。

Buffer的三个属性:

  • capacity:固定的大小值

  • position:当读取数据时,也是从某个特定位置读。当将Buffer从写模式切换到读模式,position会被重置为0。当从Buffer的position处读取数据时,position向前移动到下一个可读的位置。

  • limit:在写模式下,Buffer的limit表示你最多能往Buffer里写多少数据。 写模式下,limit等于Buffer的capacity。当切换Buffer到读模式时, limit表示你最多能读到多少数据。因此,当切换Buffer到读模式时,limit会被设置成写模式下的position值。换句话说,你能读

      到之前写入的所有数据(limit被设置成已写数据的数量,这个值在写模式下就是position)

scatter,gather:channel从buffer中读取,写入数据

ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body = ByteBuffer.allocate(1024);
ByteBuffer[] bufferArray = { header, body };
channel.write(bufferArray);//写入到channel
channel.read(bufferArray);//写入到buffer

通道之间的数据传输   :SocketChannel会一直传输数据直到目标buffer被填满。

transFrom()

transTo()

RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw");
FileChannel fromChannel = fromFile.getChannel();
RandomAccessFile toFile = new RandomAccessFile("toFile.txt", "rw");
FileChannel toChannel = toFile.getChannel();
long position = 0;
long count = fromChannel.size();
toChannel.transferFrom(position, count, fromChannel);
fromChannel.transferTo(position, count, toChannel);

Selector(选择器)

selector是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写设备准备好的组建,这样,一个单独的线程可以管理多个channel,从而管理多个网络连接。

创建selector:Selector selector = Selector.open();

向selector注册通道:

channel.configureBlocking(false);//与Selector使用时,Channel必须处于非阻塞模式下,套接字通道可以,FileChannel不可以切换
SelectionKey key = channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);

SelectionKey:注册时,register()方法会返回一个SelectionKey,它包含一些你感兴趣的属性:

        interest集合:是你所选择的感兴趣的事件集合,可以监听四种不同类型的事件(Connect,Accept,Read,Write)

        ready集合:是通道已经准备就绪的操作集合,可通过四个方法检测channel中什么事件或操纵已经就绪

            • selectionKey.isAcceptable();
            • selectionKey.isConnectable();
            • selectionKey.isReadable();
            • selectionKey.isWritable();

        Channel:

                Channel channel = selectionKey.channel();

        Selector:

                Selector selector = selectionKey.selector();

        附加对象(可选):selectionKey.attach(theObject);     Object attachedObj = selectionKey.attachment();

通过Selector选择通道

select()方法:

  • select()阻塞到至少有一个通道在你注册的事件上就绪了。 返回的int值表示有多少通道已经就绪了。
  • select(long timeout)和select()一样,除了最长会阻塞timeout毫秒(参数)。
  • selectNow()不会阻塞,不管什么通道就绪都立刻返回(译者注:此方法执行非阻塞的选择操作。如果自从前一次选择操作后,没有通道变成可选择的,则此方法直接返回零。)。

selectedKeys():调用select()方法后,根据得到有多少个通道就绪了,然后可以通过selector的selectedKeys()方法,访问已选择键集中的就绪通道

Set selectedKeys = selector.selectedKeys();  

当像Selector注册Channel时,Channel.register()方法会返回一个SelectionKey 对象。这个对象代表了注册到该Selector的通道。可以通过SelectionKey的selectedKeySet()方法访问这些对象。
可以遍历这个已选择的键集合来访问就绪的通道。打开一个Selector,注册一个通道注册到这个Selector上(通道的初始化过程略去),然后持续监控这个Selector的四种事件(接受,连接,读,写)是否就绪。如下:

  1. Selector selector = Selector.open();
  2. channel.configureBlocking(false);
  3. SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
  4. while(true) {
  5. int readyChannels = selector.select();
  6. if(readyChannels == 0) continue;
  7. Set selectedKeys = selector.selectedKeys();
  8. Iterator keyIterator = selectedKeys.iterator();
  9. while(keyIterator.hasNext()) {
  10. SelectionKey key = keyIterator.next();
  11. if(key.isAcceptable()) {
  12. // a connection was accepted by a ServerSocketChannel.
  13. } else if (key.isConnectable()) {
  14. // a connection was established with a remote server.
  15. } else if (key.isReadable()) {
  16. // a channel is ready for reading
  17. } else if (key.isWritable()) {
  18. // a channel is ready for writing
  19. }
  20. keyIterator.<tuihighlight class="tuihighlight"><a href="javascript:;" style="display:inline;float:none;position:inherit;cursor:pointer;color:#7962D5;text-decoration:underline;" onclick="return false;">remove</a></tuihighlight>();
  21. }
  22. }

SelectionKey.channel()方法返回的通道需要转型成你要处理的类型,如ServerSocketChannel或SocketChannel等。

文件通道

FileChannel无法设置为非阻塞模式,它总是运行在阻塞模式下。

打开channel:需要通过使用一个InputStream,OutputStream或RandomAccessFile来获取一个FileChannel实例

RandomAccessFile aFile = new RandomAccessFile("xx.txt, "rw");
FileChannel inChannel = aFile.getChannel();

从FileChannel中读取数据

ByteBuffer buf = ByteBuffer.allocate(48);
int byteRead = inChannel.read(buf); //表示有多少分字节被读到Buffer中

向FileChannel写数据

String newData = "new String to write to file ..." + System.currentTimeMills();
long pos = channel.position(); //FileChannel的当前位置
channel.position(pos + 123); //设置FileChannel的当前位置
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();
while(buf.hasRemaining()){
channel.write(buf);
}

关闭FileChannel

channel.close();

截取文件,文件将指定长度后面的部分被删除

channel.truncate(1024);

强制写入磁盘:FileChannel.force()方法将通道里尚未写入磁盘的数据强制写到磁盘上。出于性能方面的考虑,操作系统会将数据缓存在内存中,所以无法保证写入到FileChannel里的数据一定会即时写到磁盘上。

要保证这一点,需要调用force()方法。force()方法有一个boolean类型的参数,指明是否同时将文件元数据(权限信息等)写到磁盘上。 下面的例子同时将文件数据和元数据强制写到磁盘上:

channel.force(true);

 

Java NIO学习的更多相关文章

  1. Java NIO学习与记录(八): Reactor两种多线程模型的实现

    Reactor两种多线程模型的实现 注:本篇文章例子基于上一篇进行:Java NIO学习与记录(七): Reactor单线程模型的实现 紧接着上篇Reactor单线程模型的例子来,假设Handler的 ...

  2. Java NIO学习笔记

    Java NIO学习笔记 一 基本概念 IO 是主存和外部设备 ( 硬盘.终端和网络等 ) 拷贝数据的过程. IO 是操作系统的底层功能实现,底层通过 I/O 指令进行完成. 所有语言运行时系统提供执 ...

  3. 零拷贝详解 Java NIO学习笔记四(零拷贝详解)

    转 https://blog.csdn.net/u013096088/article/details/79122671 Java NIO学习笔记四(零拷贝详解) 2018年01月21日 20:20:5 ...

  4. Java NIO 学习笔记(七)----NIO/IO 的对比和总结

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

  5. Java NIO 学习笔记(六)----异步文件通道 AsynchronousFileChannel

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

  6. Java NIO 学习笔记(五)----路径、文件和管道 Path/Files/Pipe

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

  7. Java NIO 学习笔记(四)----文件通道和网络通道

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

  8. Java NIO 学习笔记(三)----Selector

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

  9. Java NIO 学习笔记(二)----聚集和分散,通道到通道

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

  10. Java NIO 学习笔记(一)----概述,Channel/Buffer

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

随机推荐

  1. ES6入门之Proxy

    1. 概述 Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种『元编程』即对编程语言进行编程. 1.1 理解 Proxy 是在目标对象之前架设一层『拦截』,外部对对象的访问 ...

  2. 好用的 python 工具集合

    图标处理小程序, 妈妈再也不用担心我不会制作图标了 # PythonMargick包可以到Unofficial Windows Binaries for Python Extension Packag ...

  3. Alpha阶段评审

    组别  项目名称 学生互评 助教评分 点评建议 第1组 校园物资共享平台 7.97 6.17 界面较为简洁美观,实现物品信息发布,登录注册和个人信息等功能,交易功能待完善: 博客内容比较完善,有alp ...

  4. 利用druid sql parser搞一些事情

    在最近的项目开发中,有这样一个需求,就是给定一个查询的sql,在where语句中添加几个条件语句.刚开始想的是,是否能用正则去做这个事情呢?其实不用语法树还是有一点困难的. 经过一系列google,看 ...

  5. ssh无密码访问设置(ssh-keygen 的详解)

    [原文链接]http://blog.csdn.net/wh_19910525/article/details/7433164 为了让两个linux机器之间使用ssh不需要用户名和密码.所以采用了数字签 ...

  6. 关于windows下无法删除文件,需要TrueInstaller权限的问题

    笔者办公室的笔记本今天突然弹出来一个ie浏览器,这不是为了下载其他浏览器而存在的浏览器吗?现在还臭不要脸的弹出来,然鹅我在删除文件夹的时候,提示我无法删除,必须要有TrueInstaller的权限,那 ...

  7. Logback日志输出到ELK

    用docker-compose本机部署elk docker-compose.yml version: "3" services: es01: image: docker.elast ...

  8. Python 3.8测试阶段正式开始,发布Beta 1版

    上周,Python背后的团队宣布发布了Python 3.8.0b1 版本,这是Python 3.8计划的四个beta发行预览版中的第一个.此版本标志着beta阶段的开始,您可以在此阶段测试新特性,并使 ...

  9. 团队作业-Beta冲刺(周五)

    一. 这个作业属于哪个课程 https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass1/ 这个作业要求在哪里 https://edu.c ...

  10. P2197 【模板】nim游戏

    博弈初心者... 学习地址luogu上可以找到.关于比较好的证明地址放在了地址页里了.这里不再赘述. 大概感觉还是所谓先手必胜就是面对当前局面一定可以采取一种策略,然后后手无论再怎么做,先手都可以“控 ...