Java NIO 中通道(Channel)的使用
阿新 • • 發佈:2019-02-20
通道(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));
}
}