Java Nio 特性学习(一)

Java NIO 特性学习

Java NIO 包含几个核心的组件:

  • Channels
  • Buffer
  • Selectors

Channels

可以理解为资源的一个流,通过这个流资源可以从Channel读取Data到一个Buffer中或者从一个Buffer中写入Data到Channel;

Channel Implementations

集中Jdk7常用的Channel上线

  • FileChannel : 操作文件读取或者写入数据
  • DatagramChannel : 从一个网络UDP连接中读取或写入数据
  • SocketChannel : 从一个TCP网络连接中读取或写入数据
  • ServerSocketChannel: 可以使用这个Channel来监听TCP连接,如同Web Server 当连接来时可以创建出一个SocketChannel

Base Channel Example

Read Data from Channel

  1. RandomAccessFile
    aFile =newRandomAccessFile("data/nio-data.txt","rw");
  2. FileChannel
    inChannel = aFile.getChannel();
  3. ByteBuffer
    buf =ByteBuffer.allocate(48);
  4. //write
    data to buffer
  5. int
    bytesRead = inChannel.read(buf);
  6. while(bytesRead!=-1){
  7. System.out.println("Read
    " + bytesRead);
  8. //swither
    buffer type to read data from buffer
  9. buf.flip();
  10. while(buf.hasRemaining()){
  11. System.out.print((char)
    buf.get());
  12. }
  13. buf.clear();
  14. bytesRead=
    inChannel.read(buf);
  15. }
  16. aFile.close();

Buffer

Java NIO Buffers 和Channels配合使用,Read from channels into buffer ,writtern from buffers into channels

Buffer Usage

  1. 向buffer中写入数据
  2. 调用buffer.flip()方法
  3. 使用buffer.get()方法获取出数据
  4. 调用buffer.clear() 或者 buffer.compact()清理已经读取的数据

  1. RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt" , "rw");
  2. FileChannel inChannel = aFile.getChannel();
  3. //Create Buffer with capacity of 48 byte
  4. ByteBuffer buf = ByteBuffer.allocate(48);
  5. int bytesRead = inChannel.read(buf);
  6. while(bytesRead!=-1){
  7. buf.flip(); //make buffer ready for read
  8. while(buf.hasRemaining()){
  9. System.out.print((char) buf.get()); // read 1 byte at a time
  10. }
  11. buf.clear(); //make buffer ready for writing
  12. bytesRead = inChannel.read(buf);
  13. }

Buffer Capacity , Position and Limit

Capacity

Buffer在创建的时候会分配规定大小的内存块,并且在buffer写入数据时只能写入这个固定大小的数据。如果Buffer已经放满数据,就需要先read 或者 clear 只能才能继续写入。

Position

Position 在读模式和模式下面含义不一样。Bufer init之后Position值为0,当数据写入one byte ,long etc Buffer Position相应的移动到下一个位置。并且Position<=Capacity-1

当调用filp()从Buffer读取数据时会set position = 0,position会随着读取过程向下移动;

Limit

在Write模式下,Limit等于Capacity的值,表示能写多少数据到Buffer中。

调用filp()进入Reade模式会set limit = position ,表示最多能读的数据量。

常用的Buffer 实现

  • ByteBuffer
  • MappedByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer

SomeMethods of Buffer

Allocating a Buffer

通过使用allocate() 来分配Buffer大小

ByteBuffer buf = ByteBuffer.allocate(48);

CharBuffer buf = CharBuffer.allocate(1024);

Write Data to a Buffer

向Buffer中写入数据有两种方法:

  • 从Channel中读取数据写入Buffer
  • 调用Buffer put() 方法写入数据

int bytesRead = inChannel.read(buf); //read into buffer.

buf.put(127);

flip()

转换写状态到读状态,发生动作:set limit = position ; set position=0 ;

Reading Data from a Buffer

两种方法:

  • 从Buffer中读取数据到Channel
  • 读取Buffer中数据给自己,可以使用buffer自带方法 get() etc

//read from buffer into channel.

int bytesWritten = inChannel.write(buf);

byte aByte = buf.get();

rewind()

set position=0

mark() 和 reset()

mark用于打点记录position为止,之后使用reset方法可以将position重置到mark记录的位置。

Scatter / Gather /Transfers

Channel 可以执行读取操作将数据读取到多个Buffer中。

Channel 可以执行写操作将多个Buffer的数据写入Channle中。

Channel 可以在Channle之间做转换包括transferFrom() & transferTo

Scatter Reads :

例如我将html的header部分读取到第一个buffer中,将body部分读取到第二个Buffer中



  1. ByteBuffer header = ByteBuffer.allocate(128);
  2. ByteBuffer body = ByteBuffer.allocate(1024);
  3. ByteBuffer[] bufferArray = { header, body };
  4. channel.read(buffers);

Gather Writes



  1. ByteBuffer header = ByteBuffer.allocate(128);
  2. ByteBuffer body = ByteBuffer.allocate(1024);
  3. //write data into buffers
  4. ByteBuffer[] bufferArray = { header, body };
  5. channel.write(buffers);

Transfers

TransferFrom()


  1. RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw");
  2. FileChannel fromChannel = fromFile.getChannel();
  3. RandomAccessFile toFile = new RandomAccessFile("toFile.txt", "rw");
  4. FileChannel toChannel = toFile.getChannel();
  5. long position = 0;
  6. long count = fromChannel.size();
  7. toChannel.transferFrom(fromChannel, position, count);

TransferTo()


  1. RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw");
  2. FileChannel fromChannel = fromFile.getChannel();
  3. RandomAccessFile toFile = new RandomAccessFile("toFile.txt", "rw");
  4. FileChannel toChannel = toFile.getChannel();
  5. long position = 0;
  6. long count = fromChannel.size();
  7. fromChannel.transferTo(position, count, toChannel);

Selector

Selector组件可以运行判断多个Channel,动态决定使用哪个Channel来执行Read 或者 Write操作。通过这个组件可以上线一个Thread 管理多个Channels 或者 多个网络连接Channel。

Create a Selector

通过使用Selector.open()方法来创建一个Selector

Selector selector = Selector.open();

注册Channels到Selector上

为了能让Selector管理Channels需要调用Selector.register()注册到Selector

channel.configureBlocking(false); //The Channel must be in non-blocking mode to be used with a Selector

SelectionKey key = channel.register(selector, SelectionKey.OP_READ);

注册Channel的时候需要制定Channel需要关心的事件,事件包括:

  • Connect -> SelectionKey.OP_CONNECT
  • Accept -> SelectionKey.OP_ACCEPT
  • Read -> SelectionKey.OP_READ
  • Write ->SelectionKey.OP_WRITE

    如果注册多个事件可以使用 int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE; 通过int interestSet = selectionKey.interestOps(); 可以得到所有Selector’s的事件。

Simple Demo:


    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<SelectionKey> selectedKeys = selector.selectedKeys();
    8. Iterator<SelectionKey> 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.remove();
    21. }
    22. }
  • 版权声明:本文为博主原创文章,未经博主允许不得转载。

    时间: 2024-10-19 19:08:48

    Java Nio 特性学习(一)的相关文章

    Java NIO 缓冲区学习笔记

    Buffer其实就是是一个容器对象,它包含一些要写入或者刚读出的数据.在NIO中加入Buffer对象,体现了新库与原I/O的一个重要区别.在面向流的I/O中,您将数据直接写入或者将数据直接读到Stream对象中. 在NIO库中,所有数据都是用缓冲区处理的.在读取数据时,它是直接读到缓冲区中的.在写入数据时,它是写入到缓冲区中的.任何时候访问NIO中的数据,您都是将它放到缓冲区中. 缓冲区实质上是一个数组.通常它是一个字节数组,但是也可以使用其他种类的数组.但是一个缓冲区不仅仅是一个数组.缓冲区提

    Java NIO 完全学习笔记(转)

    本篇博客依照 Java NIO Tutorial翻译,算是学习 Java NIO 的一个读书笔记.建议大家可以去阅读原文,相信你肯定会受益良多. 1. Java NIO Tutorial Java NIO,被称为新 IO(New IO),是 Java 1.4 引入的,用来替代 IO API的. Java NIO:Channels and Buffers 标准的 Java IO API ,你操作的对象是字节流(byte stream)或者字符流(character stream),而 NIO,你操

    java NIO FileChannel 学习笔记 FileChannel 简介

    java NIO 中FileChannel 的实现类是  FileChannelImpl,FileChannel本身是一个抽象类. 先介绍FileChannel File Channels 是线程安全的.Channel的close方法可以随时执行(正如Channel接口所要求的).任何企图修改filechannel 对应文件大小 或者修改 filechannel position的操作都必须串行执行,第二个操作会一直阻塞直到前一个运行完.不过这些方法,具体还要看如何实现.(下文分析FileCha

    java 新特性学习笔记

    java 1.7 Files.write(path,list,StandardCharsets.UTF_8,StandardOpenOption.APPEND); String preTime = Files.readAllLines(path).get(0); LocalDate date1 = LocalDate.parse(preTime,DateTimeFormatter.BASIC_ISO_DATE); //如果时间记录存在,取出上一次操作时间+1天 date = date1.plus

    【Java语言特性学习之二】反射

    一.概念java加载class文件分两种情况:(1)类型是编译器已知的,这种文件的.class文件在编译的时候,编译器会把.class文件打开(不加载)检查,称为Run- Time Type Identification 运行时类型识别(2)从其它地方获取引用,然后动态的把这个未知类型的引用的对象的.class文件加载进jvm虚拟机里,称为反射: 在运行状态中,动态获取类信息(属性.方法)及动态调用类对象方法的功能称为java的反射机制. 二.反射APIJava反射包:java.lang.ref

    【Java语言特性学习之四】JUC

    一.JUC 简介 在Java5.0提供了java.util.concurrent(简称JUC)包,在此包中增加了并发编程常用工具类,包括线程池,异步IO和轻量级任务框架;还提供了设计用于多线程上下文中的Collection实现等.目的就是为了更好的支持高并发任务,让开发者利用这个包进行的多线程编程时可以有效的减少竞争条件和死锁线程. 按照功能可以大致划分如下:juc-locks 锁框架juc-atomic 原子类框架juc-sync(tools) 同步器框架juc-collections 集合框

    Java NIO、NIO.2学习笔记

    相关学习资料 http://www.molotang.com/articles/903.html http://www.ibm.com/developerworks/cn/education/java/j-nio/j-nio.html 目录 1. NIO.NIO.2简介 2. NIO中的关键技术 1. NIO.NIO.2简介 Java中的输入流.输出流都是阻塞式的输入.输出.不仅如此,传统的输入流.输出流都是通过字节的移动来处理的(即使是字符流,在底层也是通过字节流来进行处理的),也就是说,面向

    通过Tomcat的Http11NioProtocol源码学习Java NIO设计

    Tomcat的Http11NioProtocol协议使用Java NIO技术实现高性能Web服务器.本文通过分析Http11NioProtocol源码来学习Java NIO的使用.从中可以了解到阻塞IO和非阻塞IO的配合,NIO的读写操作以及Selector.wakeup的使用. 1. 初始化阶段 Java NIO服务器端实现的第一步是开启一个新的ServerSocketChannel对象.Http11NioProtocol的实现也不例外, 在NioEndPoint类的init方法可以看到这段代

    java nio学习笔记(一)

    位置保留,待用 java nio学习笔记(一),布布扣,bubuko.com