java.nio基础篇之Buffer


很好的学习资料

http://tutorials.jenkov.com/java-nio/index.html


本文主要是对java.nio的全貌做个简单介绍 然后详细介绍Buffer方法 并测试Buffer的相关方法

Java nio (new io) 对于java io和 java networking而言,是一个可选的io api

核心组件有三个Buffers Channels Selectors
Buffers
	缓存主要有
	ByteBuffer CharBuffer ShortBuffer IntBuffer FloatBuffer LongBuffer DoubleBuffer
	覆盖基本的数据类型  byte character short int float long double
Channels
	通道主要有
	  FileChannel  DatagramChannel  ServerChannel  ServerSocketChannel
	包含file io、udp、tcp三类

	
Selectors
	多路复用器或者称为选择器
	可以使一个线程使用多路复用器处理多个通道


Buffer与Channel的关系如下

java.nio基础篇之Buffer_第1张图片


对于Scatter与Gather模式的描述

A "scattering read" reads data from a single channel into multiple buffers
A "gathering write" writes data from multiple buffers into a single channel. 


两者的关系图

java.nio基础篇之Buffer_第2张图片


java.nio基础篇之Buffer_第3张图片



Channel与Selector的关系如下

java.nio基础篇之Buffer_第4张图片


下面是关于Buffer的各种方法的描述

Buffer中搞清楚 position  limit  capacity 的意思 在读写模式中的位置  理解Buffer的方法 就很简单了


Basic Buffer Usage

源文档  


1. Write data into the Buffer
2. Call buffer.flip()
3. Read data out of the Buffer
4. Call buffer.clear() or buffer.compact()

源文档  

Initially the position is 0,Position can maximally become capacity - 1

1. Write data from a Channel into a Buffer
2. Write data into the Buffer yourself, via the buffer's put() methods.

源文档  

The flip() method switches a Buffer from writing mode to reading mode. Calling flip() sets the position back to 0, and sets the limit to where position just was.


3. Read data from the buffer into a channel.
4. Read data from the buffer yourself, using one of the get() methods.

The Buffer.rewind() sets the position back to 0, so you can reread all the data in the buffer. The limit remains untouched, thus still marking how many elements (bytes, chars etc.) that can be read from the Buffer. 


clear() and compact()

If you call clear() the position is set back to 0 and the limit to capacity. In other words, the Buffer is cleared. The data in the Buffer is not cleared. Only the markers telling where you can write data into the Buffer are.

compact() copies all unread data to the beginning of the Buffer. Then it sets position to right after the last unread element. The limit property is still set to capacity, just like clear() does. Now the Buffer is ready for writing, but you will not overwrite the unread data. 

mark() and reset()

You can mark a given position in a Buffer by calling the Buffer.mark() method. You can then later reset the position back to the marked position by calling the Buffer.reset() method

equals() and compareTo()

equals()
Two buffers are equal if: 
5. They are of the same type (byte, char, int etc.)
6. They have the same amount of remaining bytes, chars etc. in the buffer.
7. All remaining bytes, chars etc. are equal.

compareTo()
The compareTo() method compares the remaining elements (bytes, chars etc.) of the two buffers, for use in e.g. sorting routines. A buffer is considered "smaller" than another buffer if: 
8. The first element which is equal to the corresponding element in the other buffer, is smaller than that in the other buffer.
9. All elements are equal, but the first buffer runs out of elements before the second buffer does (it has fewer elements).

源文档  


上面都是每个方法比较重要的描述 

Buffer的读模式与写模式的 position  limit capacity 三者间的关系图

java.nio基础篇之Buffer_第5张图片





最后一一些单元测试  都加了代码注释

package com.undergrowth;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class BasicChannel {

	RandomAccessFile randomAccessFile,randomAccessFile2;
	FileChannel fileChannel,fileChannel2;
	ByteBuffer buffer, buffer2;

	/**
	 * 测试之前打开文件 分配buffer
	 * 
	 * @throws FileNotFoundException
	 */
	@Before
	public void before() throws FileNotFoundException {
		randomAccessFile = new RandomAccessFile(ClassLoader.getSystemResource(
				"channel.xml").getFile(), "rw");
		randomAccessFile2 = new RandomAccessFile(ClassLoader.getSystemResource(
				"channel2.xml").getFile(), "rw");
		fileChannel = randomAccessFile.getChannel();
		fileChannel2 = randomAccessFile2.getChannel();
		buffer = ByteBuffer.allocate(1024);
		buffer2 = ByteBuffer.allocate(512);
	}

	/**
	 * 测试完成后 关闭文件
	 * 
	 * @throws IOException
	 */
	@After
	public void after() throws IOException {
		fileChannel.close();
		fileChannel2.close();
		randomAccessFile.close();
		randomAccessFile2.close();
	}

	/**
	 * 测试读写
	 */
	@Test
	public void testRead() {
		// TODO Auto-generated method stub
		try {
			System.out.println(readBuffer(fileChannel, buffer));
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}

	/**
	 * 测试标记与重置 You can mark a given position in a Buffer by calling the
	 * Buffer.mark() method. You can then later reset the position back to the
	 * marked position by calling the Buffer.reset() method
	 * 
	 * @throws IOException
	 */
	@Test
	public void testMarkReset() throws IOException {
		int byteRead = fileChannel.read(buffer);
		if (byteRead != -1) {
			// 反转buffer模式
			buffer.flip();
			while (buffer.hasRemaining()) {
				char tmp = (char) buffer.get();
				// 当出现9字符的时候 进行标注
				if (tmp == '9')
					buffer.mark();
				System.out.print(tmp);
			}
			// 将buffer的position置为9字符的位置
			buffer.reset();
			System.out.println();
			System.out.println("置为9字符的起始位置开始读取数据");
			while (buffer.hasRemaining())
				System.out.print((char) buffer.get());
		}
	}

	/**
	 * 测试equals和compareTo 这两个方法都是比较剩余元素 equals() Two buffers are equal if: 5.
	 * They are of the same type (byte, char, int etc.) 6. They have the same
	 * amount of remaining bytes, chars etc. in the buffer. 7. All remaining
	 * bytes, chars etc. are equal.
	 * 
	 * compareTo() The compareTo() method compares the remaining elements
	 * (bytes, chars etc.) of the two buffers, for use in e.g. sorting routines.
	 * A buffer is considered "smaller" than another buffer if: 8. The first
	 * element which is equal to the corresponding element in the other buffer,
	 * is smaller than that in the other buffer. 9. All elements are equal, but
	 * the first buffer runs out of elements before the second buffer does (it
	 * has fewer elements).
	 * 
	 * @throws IOException
	 */
	@Test
	public void testEqualsCompare() throws IOException {
		int byteRead = fileChannel.read(buffer);
		buffer2.put((byte) 'q');
		int byteRead2 = fileChannel.read(buffer2);
		if (byteRead != -1 && byteRead2 != -1) {
			buffer.flip();
			buffer2.flip();
			System.out.println("剩下元素");
			System.out.println(buffer.remaining());
			System.out.println(buffer2.remaining());
			// 比较两个buffer是否相等
			System.out.println();
			System.out.println(buffer.equals(buffer2));
			System.out.println(buffer.compareTo(buffer2));
		}
	}

	/**
	 * 测试重置方法 The Buffer.rewind() sets the position back to 0, so you can reread
	 * all the data in the buffer. The limit remains untouched, thus still
	 * marking how many elements (bytes, chars etc.) that can be read from the
	 * Buffer.
	 * 
	 * @throws IOException
	 */
	@Test
	public void testRewind() throws IOException {
		int byteRead = fileChannel.read(buffer);
		if (byteRead != -1) {
			// 反转buffer模式
			buffer.flip();
			while (buffer.hasRemaining())
				System.out.print((char) buffer.get());
			// 重新读取buffer
			System.out.println();
			System.out.println("重新读取buffer");
			// 将buffer的positon置为0
			buffer.rewind();
			while (buffer.hasRemaining())
				System.out.print((char) buffer.get());

		}
	}

	/**
	 * 将文件通道的内容读入到缓存中 从缓存中读出数据 返回 If you call clear() the position is set back
	 * to 0 and the limit to capacity. In other words, the Buffer is cleared.
	 * The data in the Buffer is not cleared. Only the markers telling where you
	 * can write data into the Buffer are.
	 * 
	 * 
	 * compact() copies all unread data to the beginning of the Buffer. Then it
	 * sets position to right after the last unread element. The limit property
	 * is still set to capacity, just like clear() does. Now the Buffer is ready
	 * for writing, but you will not overwrite the unread data.
	 * 
	 * @param fileChannel
	 * @param buffer
	 * @return
	 * @throws IOException
	 */
	public String readBuffer(FileChannel fileChannel, ByteBuffer buffer)
			throws IOException {
		StringBuilder builder = new StringBuilder();
		// 1、读入数据到缓存中
		int byteRead = fileChannel.read(buffer);
		while (byteRead != -1) {
			// 2、转换缓存的模式
			buffer.flip();
			// 3、从缓存中读出数据
			while (buffer.hasRemaining())
				builder.append((char) buffer.get());

			// 4、清除缓冲区
			buffer.clear();
			byteRead = fileChannel.read(buffer);
		}
		// System.out.println(builder.toString());
		return builder.toString();
	}
	
	@Test
	public void testWriteBuffer() throws IOException{
		buffer.put((byte)'1');
		buffer.put((byte)'2');
		buffer.put((byte)'3');
		buffer.put((byte)'4');
		System.out.println(fileChannel.write(buffer));
	}
	
	/**
	 * Scatter和Gather模式
	 * Scatter Read支持从一个通道读取到多个缓存区
	 * Gather Write支持从多个缓存区将数据写入到一个通道中
	 * @throws IOException
	 */
	@Test
	public void testScatterGather() throws IOException{
		//构建buffer数组
		ByteBuffer[] buffers={buffer,buffer2};
		//读数据到多个缓存中
		System.out.println(fileChannel.read(buffers));;
		//转换缓存模式
		buffer.flip();
		buffer2.flip();
		//读取缓存数据
		System.out.println("缓存1");
		while(buffer.hasRemaining()) System.out.print((char)buffer.get());
        buffer.rewind();
        System.out.println();
        System.out.println("缓存1和2");
        while(buffer.hasRemaining()) System.out.print((char)buffer.get());
		while(buffer2.hasRemaining()) System.out.print((char)buffer2.get());
		buffer.rewind();
		buffer2.rewind();
		System.out.println();
		System.out.println("字符集输出");
		System.out.println(Charset.defaultCharset().decode(buffer));
		buffer.rewind();
		buffer2.rewind();
		//写缓存数据
		fileChannel2.write(buffers);
		
	}
	
	/**
	 * 从一个通道转换到另一个通道
	 * @throws IOException
	 */
	@Test
	public void testChannerTransfer() throws IOException{
		System.out.println(fileChannel2.transferFrom(fileChannel, 0, fileChannel.size()));;
	}
}






你可能感兴趣的:(java,java.nio)