1. 程式人生 > >Java NIO 通道(Channel) 學習筆記

Java NIO 通道(Channel) 學習筆記

 一、通道(Channel):用於源節點與目標節點的連線。在 Java NIO 中負責緩衝區中資料的傳輸。Channel 本身不儲存資料,因此需要配合緩衝區進行傳輸。
 
 二、通道的主要實現類
     java.nio.channels.Channel 介面:
         |--FileChannel
         |--SocketChannel
         |--ServerSocketChannel
         |--DatagramChannel
 
 三、獲取通道
 1. Java 針對支援通道的類提供了 getChannel() 方法
         本地 IO:
         FileInputStream/FileOutputStream
         RandomAccessFile
 
         網路IO:
         Socket
         ServerSocket
         DatagramSocket


         
 2. 在 JDK 1.7 中的 NIO.2 針對各個通道提供了靜態方法 open()
 3. 在 JDK 1.7 中的 NIO.2 的 Files 工具類的 newByteChannel()
 
 四、通道之間的資料傳輸
     transferFrom()
     transferTo()
 

 五、分散(Scatter)與聚集(Gather)
     分散讀取(Scattering Reads):
將通道中的資料分散到多個緩衝區中
     聚集寫入(Gathering Writes):將多個緩衝區中的資料聚集到通道中
 
 六、字符集:Charset
     編碼:字串 -> 位元組陣列
     解碼:位元組陣列  -> 字串
 

 

Channel程式碼例項:利用通道完成檔案的複製

1.非直接緩衝區

    //利用通道完成檔案的複製(非直接緩衝區) 
	@Test
	public void testChannel(){
		long start = System.currentTimeMillis();
		
		FileInputStream fis = null;
		FileOutputStream fos = null;
		
		//1. 獲取通道
		FileChannel inChannel = null;
		FileChannel outChannel = null;
		
		try{
			fis = new FileInputStream("G:/MP4/00.mp4");
			fos = new FileOutputStream("G:/MP4/01.mp4");
			inChannel = fis.getChannel();
			outChannel = fos.getChannel(); 
			
			//2. 分配指定大小的非直接緩衝區
			ByteBuffer buff = ByteBuffer.allocate(1024);
			
			//3. 將通道中的資料存入緩衝區中
			while(inChannel.read(buff) != -1){
				buff.flip(); //切換讀取資料的模式
				
				//4.將緩衝區中的資料寫入通道中
				outChannel.write(buff);
				buff.clear(); //清空緩衝區
			}
			
		}catch(IOException e){
			e.printStackTrace();
		}finally{
			if(fis != null){
				try {
					fis.close();
				} catch (IOException e) { 
					e.printStackTrace();
				}
			}
			
			if(fos != null){
				try {
					fos.close();
				} catch (IOException e) { 
					e.printStackTrace();
				}
			}
			
			if(inChannel != null){
				try {
					inChannel.close();
				} catch (IOException e) { 
					e.printStackTrace();
				}
			}
			if(outChannel != null){
				try {
					outChannel.close();
				} catch (IOException e) { 
					e.printStackTrace();
				}
			}
		}
		
		long end = System.currentTimeMillis();
		System.out.println("耗費時間為:" + (end - start)); 
	}   

2.直接緩衝區

    @Test
	public void testFileChannel(){
		long start = System.currentTimeMillis();
		
		try {
			FileChannel inChannel = FileChannel.open(Paths.get("G:/MP4/00.mp4"), StandardOpenOption.READ);
			FileChannel outChannel = FileChannel.open(Paths.get("G:/MP4/04.mp4"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);
			
			// start 1.第一種實現方式:使用直接緩衝區完成檔案的複製(記憶體對映檔案) 
			MappedByteBuffer inMappedBuf = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());
			MappedByteBuffer outMappedBuf = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size());
			
			//直接對緩衝區進行資料的讀寫操作
			byte[] dst = new byte[inMappedBuf.limit()];
			inMappedBuf.get(dst);    
			outMappedBuf.put(dst);   
			// end 1.第一種實現方式:使用直接緩衝區完成檔案的複製(記憶體對映檔案) 
			
			// start 2.第二種實現方式:通道之間的資料傳輸(直接緩衝區) transferTo || transferFrom
			inChannel.transferTo(0, inChannel.size(), outChannel);
//			outChannel.transferFrom(inChannel, 0, inChannel.size());
			// end 2.第二種實現方式:通道之間的資料傳輸(直接緩衝區) transferTo || transferFrom
			
			inChannel.close();
			outChannel.close();
			
			long end = System.currentTimeMillis();
			System.out.println("耗費時間為:" + (end - start));
			 
		} catch (IOException e) { 
			e.printStackTrace();
		}
	}