码迷,mamicode.com
首页 > 编程语言 > 详细

Java Nio 特性学习(一)

时间:2015-07-16 22:22:49      阅读:259      评论:0      收藏:0      [点我收藏+]

标签: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. }
  • 版权声明:本文为博主原创文章,未经博主允许不得转载。

    Java Nio 特性学习(一)

    标签:java   nio   

    原文地址:http://blog.csdn.net/yxp20092010/article/details/46916461

    (0)
    (0)
       
    举报
    评论 一句话评论(0
    登录后才能评论!
    © 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
    迷上了代码!