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