NIO学习-Channel

package nio;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

import org.junit.Test;


public class NioTest {
	/**
	 * 一.通道(channel):用于源节点与目标节点的链接在java Nio中负责缓冲区数据的传输。
	 *  channel自己不存储数据,所以须要配合缓冲区进行传输
	 * 二.通道有如下几类:
	 *  FileChannel
	 *  SocketChannel
	 *  ServerSocketChannel
	 *  DatagramChannel
	 *  
	 *  3、通道获
	 *  1.jdk 1.6如下
	 *  本地Io
	 *  FileInputStream/FileOutputStream
	 *  RandomAccessFile
	 *  网络io
	 *  2.在jdk 1.7之后
	 *  FileChannel.open(path, options)
	 *  Files.newByteChannel(path, options)
	 */
	
	/**
	 * 使用nio进行文件的复制 
	 */
	@Test
	public void test1() throws IOException {
		long startTime = System.currentTimeMillis();
		
		FileInputStream fis = new FileInputStream("file.rmvb");
		FileOutputStream fos = new FileOutputStream("file_back.rmvb");
		FileChannel sourceChannel = fis.getChannel();
		FileChannel targetChannel = fos.getChannel();
		
		ByteBuffer buffer = ByteBuffer.allocateDirect(1024*10);// 分配直接缓冲区的方式,完成时间:4秒
		buffer.isDirect();		//判断是使用直接/非直接缓冲区的方法
		//ByteBuffer buffer = ByteBuffer.allocate(1024*10); //分配非直接缓冲区的方式,完成时间20秒
		
		while (sourceChannel.read(buffer) !=-1) {
			buffer.flip();
			targetChannel.write(buffer);
			buffer.clear();
		}
		
		sourceChannel.close();
		fos.close();

		targetChannel.close();
		fis.close();
		
		long endTime= System.currentTimeMillis();
		
		System.out.println("完成复制用时:"+((endTime-startTime)/1000)+"秒");
	}
	
	/**
	 * 使用直接缓冲区完成文件的复制(内存映射文件)。
	 * 1.注意:使用直接内存映射,是直接使用操做系统的内存。当你开辟大量内存时,操做系统的内存使用率迅速上升。
	 * 可是及时文件完成了复制,内存也不会当即释放。须等到jvm的垃圾回收,因此会出现‘jvm卡内存’的状况。
	 * 使用这种方式虽然快,但十分的耗内存。
	 * 2.使用场景:在直接缓冲区能在程序性能方面带来明显好处时分配它们。
	 */
	@Test
	public void test2() throws IOException {
		// Paths 用法: Paths.get("d:/","nio/","file.rmvb");
		// StandardOpenOption :表示操做的模式
		// 1.READ 可读
		// 2.WRITE 可写,若是文件不存在就建立,存在就覆盖
		// 3.CREATE_NEW 可写,若是文件不存在就建立,不存在就报错
		long startTime = System.currentTimeMillis();
		
		FileChannel sourceChannel = FileChannel.open(Paths.get("file.rmvb"), StandardOpenOption.READ);
		FileChannel targetChannel = FileChannel.open(Paths.get("file_back.rmvb"),
				StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);
		
		//建立输出输入的映射内存
		MappedByteBuffer inMapBuffer = sourceChannel.map(MapMode.READ_ONLY, 0, sourceChannel.size());
		MappedByteBuffer outMapBuffer  = targetChannel.map(MapMode.READ_WRITE, 0, sourceChannel.size());
		
		//完成复制
		byte[] byteArr = new byte[inMapBuffer.limit()];
		inMapBuffer.get(byteArr);
		outMapBuffer.put(byteArr);
		
		sourceChannel.close();
		targetChannel.close();
		long endTime= System.currentTimeMillis();
		
		System.out.println("完成复制用时:"+((endTime-startTime)/1000)+"秒");
	}
	
	
	/**
	 * 通道之间的数据传输(使用直接缓冲区的方式)
	 * @throws IOException
	 */
	@Test
	public void test3()throws IOException {
		long startTime = System.currentTimeMillis();
		
		FileChannel sourceChannel = FileChannel.open(Paths.get("file.rmvb"), StandardOpenOption.READ);
		FileChannel targetChannel = FileChannel.open(Paths.get("file_back.rmvb"),
				StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);
		sourceChannel.transferTo(0, sourceChannel.size(), targetChannel);
		//或者targetChannel.transferFrom(sourceChannel, startTime, sourceChannel.size());
		sourceChannel.close();
		targetChannel.close();
		
		long endTime= System.currentTimeMillis();
		
		System.out.println("完成复制用时:"+((endTime-startTime)/1000)+"秒");
	}
	
	/**
	 * 分散与读取
	 * 说明:将通道中的数据分散到多个缓冲区中(使用多个buffer进行读取),顺序写入给定的buffer
	 */
	@Test
	public void test4() throws IOException{
		//1.获取源通道
		RandomAccessFile targetFile = new RandomAccessFile("JavaNIO.pdf", "rw");
		FileChannel targetChanne = targetFile.getChannel();
		
		//2.建立buffer
		ByteBuffer buf1 = ByteBuffer.allocate(1024);
		ByteBuffer buf2 = ByteBuffer.allocate(1024);
		ByteBuffer[] bufArr = {buf1,buf2};
		
		//3.建立目标通道
		RandomAccessFile sourceFile = new RandomAccessFile("JavaNIO_copy.pdf", "rw");
		FileChannel sourceChanne = sourceFile.getChannel();
		
		//4.进行【分散读取】/【汇集写入】
		while(targetChanne.read(bufArr) !=-1){
			for (ByteBuffer buf : bufArr) {
				buf.flip();
			}
			sourceChanne.write(bufArr);
			for (ByteBuffer buf : bufArr) {
				buf.clear();
			}
		}
		
		//5.关闭
		sourceChanne.close();
		sourceFile.close();
		targetChanne.close();
		targetFile.close();
	}
	
	/**
	 * 通道用户操做本地文件的编码与解码( Charset) 
	 * 编码: 字符串 -> 字节数组
	 * 解码:字节数组 -> 字符组
	 */
	@Test
	public void test5() throws IOException{
		Charset charset = Charset.forName("utf-8");
		
		//获取编码器
		CharsetEncoder encoder = charset.newEncoder();
		
		CharBuffer charBuffer = CharBuffer.allocate(1024);
		charBuffer.put("字符集 Charset学习");
		charBuffer.flip();
		
		ByteBuffer enBuffer = encoder.encode(charBuffer);
		
		for (int i = 0; i <enBuffer.limit(); i++) {
			System.out.println(enBuffer.get());
		}
		
		System.out.println("解码:");
		//获取解码器
		CharsetDecoder decoder = charset.newDecoder();
		enBuffer.flip();
		CharBuffer deBuffer = decoder.decode(enBuffer);
		System.out.println(deBuffer.toString());
		
	}
	

	
}
相关文章
相关标签/搜索