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());
		
	}
	

	
}
相關文章
相關標籤/搜索