NIO Channel
阿新 • • 發佈:2019-10-02
在傳統IO中, 若有大量IO操作, 會佔用cpu資源, 效能下降
使用DMA時, 由DMA處理IO請求。但若有大量IO操作時, 會發生DMA匯流排衝突, 也會影響效能
使用Channel時,其專用於IO操作, cpu利用率更高, 效能更高
Channel的主要實現類
java.nio.channels.channel介面
|--FileChannel 本地檔案
|--SocketChannel 用於網路
|--ServerSocketChannel 用於網路
|--DatagramChannel 用於網路
java中獲取通道的方式
-
對支援通道的類提供了getChannel方法
本地IO:
- FileInputStream/FileOutputStream
- RandomAccessFile
網路IO: - Socket
- ServerSocket
- DatagramSocket
// 利用通道完成檔案的複製(非直接緩衝區) final FileInputStream fis = new FileInputStream("F:\\ProgarmData\\SystemFoler\\Pictures\\1.png"); final FileOutputStream fos = new FileOutputStream("F:\\ProgarmData\\SystemFoler\\Pictures\\2.png"); // 1.獲取通道 final FileChannel inChannel = fis.getChannel(); final FileChannel outChannel = fos.getChannel(); // 2分配指定大小的緩衝區 final ByteBuffer buf = ByteBuffer.allocate(1024); // 3.將通道中的資料存入緩衝區中 while(inChannel.read(buf) != -1){ buf.flip();//切換讀資料模式 // 4.將緩衝區的資料寫入通道中 outChannel.write(buf); buf.clear();//情況緩衝區 } outChannel.close(); inChannel.close(); fos.close(); fis.close();
-
(1.7之後)各個通道類提供了靜態方法open()
// 使用直接緩衝區完成檔案的複製(記憶體檔案對映) final FileChannel inChannel = FileChannel.open(Paths.get("F:\\ProgarmData\\SystemFoler\\Pictures\\1.png"), StandardOpenOption.READ); final FileChannel outChannel = FileChannel.open(Paths.get("F:\\ProgarmData\\SystemFoler\\Pictures\\3.png"), StandardOpenOption.WRITE, StandardOpenOption.READ,StandardOpenOption.CREATE_NEW); //記憶體對映檔案 final MappedByteBuffer inMappedBuffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size()); final MappedByteBuffer outMappedBuffer = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size()); // 直接對緩衝區進行資料的讀寫操作 byte[] dst = new byte[inMappedBuffer.limit()]; inMappedBuffer.get(dst); outMappedBuffer.put(dst); inChannel.close(); outChannel.close();
-
(1.7之後)Files工具類的newBytesChannel()
通道之間的資料傳輸
transferFrom() 從其他通道傳入
transferTo() 傳向其他通道
final FileChannel inChannel = FileChannel.open(Paths.get("F:\\ProgarmData\\SystemFoler\\Pictures\\1.png"), StandardOpenOption.READ);
final FileChannel outChannel = FileChannel.open(Paths.get("F:\\ProgarmData\\SystemFoler\\Pictures\\5.png"), StandardOpenOption.WRITE, StandardOpenOption.READ,StandardOpenOption.CREATE_NEW);
// inChannel.transferTo(0, inChannel.size(), outChannel);
outChannel.transferFrom(inChannel, 0, inChannel.size());
inChannel.close();
outChannel.close();
分散與聚集
分散讀取 Scattering Reads : 將通道中的資料分散到多個緩衝區中
聚集寫入 Gathering Writes : 將多個緩衝區中的資料聚集到通道中
// 獲取通道
final RandomAccessFile raf1 = new RandomAccessFile("D:\\weblog.txt", "rw");
final FileChannel channel = raf1.getChannel();
// 分配指定大小的緩衝區
final ByteBuffer buf1 = ByteBuffer.allocate(100);
final ByteBuffer buf2 = ByteBuffer.allocate(1024);
// 分散讀取
ByteBuffer[] bufs = {buf1, buf2};
channel.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()));
// 聚集寫入
final RandomAccessFile raf2 = new RandomAccessFile("D:\\ tt.txt", "rw");
final FileChannel channel2 = raf2.getChannel();
channel2.write(bufs);
字符集
編碼: 字串 -> 位元組陣列
解碼: 位元組資料 -> 字串
final Charset cs1 = Charset.forName("GBK");
// 獲取編碼器
final CharsetEncoder ce = cs1.newEncoder();
// 獲取解碼器
final CharsetDecoder cd = cs1.newDecoder();
final CharBuffer buf = CharBuffer.allocate(1024);
buf.put("呵呵噠");
buf.flip();
// 編碼
final ByteBuffer bBuf = ce.encode(buf);
// 解碼
final CharBuffer buf2 = cd.decode(bBuf);
System.out.println(buf2.toString());
final Charset cs2 = Charset.forName("utf-8");
bBuf.rewind();
final CharBuffer buf3 = cs2.decode(bBuf);
System.out.println(buf3.toStri