1. 程式人生 > >Java NIO 中通道(Channel)的使用

Java NIO 中通道(Channel)的使用

通道(Channel)的使用說明

/**
 * <pre>
 * 一、通道(Channel):用於源節點與目標節點的連線。在 Java NIO 中負責緩衝區中資料的傳輸。
 *                    Channel 本身不儲存資料,因此需要配合緩衝區進行傳輸。
 * 
 * 二、通道的主要實現類
 *  java.nio.channels.Channel 介面:
 *      |--FileChannel 用於檔案的讀寫
 *      |--SocketChannel 通過TCP讀寫網路中的資料      
 *      |--DatagramChannel 用於UDP讀寫網路中的資料
 *      |--ServerSocketChannel 主要用於服務端:可以監聽新進來的TCP連線,像Web伺服器那樣。對每一個新進來的連線都會建立一個SocketChannel。
 * 
 * 三、獲取通道
 * 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
 * 編碼:字串 -> 位元組陣列
 * 解碼:位元組陣列  -> 字串
 * </pre>
 */

程式碼示例:

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.CharacterCodingException; 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 java.util.Map; import java.util.Map.Entry; import java.util.Set; import
org.junit.Test; public class TestChannel { //分散和聚集 @Test public void test4ByteBuffer() throws IOException{ RandomAccessFile raf1 = new RandomAccessFile("1.txt", "rw"); //1. 獲取通道 FileChannel channel1 = raf1.getChannel(); //2. 分配指定大小的緩衝區 ByteBuffer buf1 = ByteBuffer.allocate(100); ByteBuffer buf2 = ByteBuffer.allocate(1024); //3. 分散讀取 ByteBuffer[] bufs = {buf1, buf2}; channel1.read(bufs); for (ByteBuffer byteBuffer : bufs) { byteBuffer.flip(); } System.out.println(new String(bufs[0].array(), 0, bufs[0].limit())); System.out.println("-----------------"); System.out.println(new String(bufs[1].array(), 0, bufs[1].limit())); //4. 聚集寫入 RandomAccessFile raf2 = new RandomAccessFile("2.txt", "rw"); FileChannel channel2 = raf2.getChannel(); channel2.write(bufs); } //通道之間的資料傳輸(直接緩衝區) @Test public void test3transferFrom() throws IOException{ FileChannel inChannel = FileChannel.open(Paths.get("d:/1.mkv"), StandardOpenOption.READ); FileChannel outChannel = FileChannel.open(Paths.get("d:/2.mkv"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE); // inChannel.transferTo(0, inChannel.size(), outChannel); outChannel.transferFrom(inChannel, 0, inChannel.size()); inChannel.close(); outChannel.close(); } //使用直接緩衝區完成檔案的複製(記憶體對映檔案) @Test public void test2MappedByteBuffer() throws IOException{//2127-1902-1777 long start = System.currentTimeMillis(); FileChannel inChannel = FileChannel.open(Paths.get("d:/1.mkv"), StandardOpenOption.READ); FileChannel outChannel = FileChannel.open(Paths.get("d:/2.mkv"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE); //記憶體對映檔案 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); inChannel.close(); outChannel.close(); long end = System.currentTimeMillis(); System.out.println("耗費時間為:" + (end - start)); } //利用通道完成檔案的複製(非直接緩衝區) @Test public void test1FileChannel(){//10874-10953 long start = System.currentTimeMillis(); FileInputStream fis = null; FileOutputStream fos = null; //①獲取通道 FileChannel inChannel = null; FileChannel outChannel = null; try { fis = new FileInputStream("d:/1.mkv"); fos = new FileOutputStream("d:/2.mkv"); inChannel = fis.getChannel(); outChannel = fos.getChannel(); //②分配指定大小的緩衝區 ByteBuffer buf = ByteBuffer.allocate(1024); //③將通道中的資料存入緩衝區中 while(inChannel.read(buf) != -1){ buf.flip(); //切換讀取資料的模式 //④將緩衝區中的資料寫入通道中 outChannel.write(buf); buf.clear(); //清空緩衝區 } } catch (IOException e) { e.printStackTrace(); } finally { if(outChannel != null){ try { outChannel.close(); } catch (IOException e) { e.printStackTrace(); } } if(inChannel != null){ try { inChannel.close(); } catch (IOException e) { e.printStackTrace(); } } if(fos != null){ try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } if(fis != null){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } long end = System.currentTimeMillis(); System.out.println("耗費時間為:" + (end - start)); } }