NIO即New IO,這個庫是在JDK1.4中才引入的。NIO和IO有相同的做用和目的,但實現方式不一樣,NIO主要用到的是塊,因此NIO的效率要比IO高不少。在Java API中提供了兩套NIO,一套是針對標準輸入輸出NIO,另外一套就是網絡編程NIO。編程
Buffer
是一個抽象類;
子類有:ByteBuffer
,CharBuffer
,DoubleBuffer
,FloatBuffer
,IntBuffer
,LongBuffer
,ShortBuffer
核心類(經常使用類):ByteBuffer
和CharBuffer
其中ByteBuffer
有一個子類MappedByteBuffer
(MappedByteBuffer
類可以將文件直接映射到內存中,那麼這樣咱們就能夠像訪問內存同樣訪問文件,很是方便)網絡
由於Buffer都是抽象類,沒法直接實例化。建立緩衝區要調用XxxBuffer allocate(int capacity),XxxBuffer allocateDirect(int capacity),參數是緩衝區容量。app
eg:獲取ByteBuffer
static ByteBuffer allocate(int capacity)
分配一個新的字節緩衝區(普通Buffer)
static ByteBuffer allocateDirect(int capacity)
分配新的直接字節緩衝區(直接Buffer)dom
兩者的區別:異步
public static void main(String[] args) { CharBuffer buffer = CharBuffer.allocate(8); // Buffer已經準備好了向Buffer中寫數據 寫模式 System.out.println("capacity:" + buffer.capacity()); // 8 System.out.println("limit:" + buffer.limit()); // 8 System.out.println("position:" + buffer.position()); // 0 buffer.put('a'); buffer.put('b'); buffer.put('c'); System.out.println("------------------------"); System.out.println("capacity:" + buffer.capacity()); // 8 System.out.println("limit:" + buffer.limit()); // 8 System.out.println("position:" + buffer.position()); // 3 System.out.println("------------------------"); // 切換模式 ,limit變爲position的位置而後將position變爲0 buffer.flip(); System.out.println("capacity:" + buffer.capacity()); // 8 System.out.println("limit:" + buffer.limit()); // 3 System.out.println("position:" + buffer.position()); // 0 System.out.println("------------------------"); System.out.println("------------------"); buffer.clear(); // 將postion 清 0 ,將limit = capacity System.out.println("capacity:" + buffer.capacity()); // 8 System.out.println("limit:" + buffer.limit()); // 8 System.out.println("position:" + buffer.position()); // 0 // 注意: 調用clear方法只是將讀模式改成寫模式,並不會清空緩衝區的數據 }
Channel原理相似於傳統的流對象,區別在於:
1.Channel可以將指定的部分或者所有文件映射到內存中
2.程序若是想要讀取Channel中的數據,不可以直接讀寫,必須通過Buffer
簡單來講:Channel經過Buffer(緩衝區)進行讀寫操做。read()表示讀取通道數據到緩衝區,write()表示把緩衝區數據寫入到通道。ide
inChannel.map(mode, position, size)
MappedByteBuffer mappBuffer = inChannel.map(MapMode.READ_ONLY, 0, srcFile.length());
public static void main(String[] args) throws IOException { File srcFile = new File("nio-a.txt"); FileInputStream fis = new FileInputStream(srcFile); FileOutputStream fos = new FileOutputStream(new File("nio-b.txt")); // 獲取Channel對象 FileChannel inChannel = fis.getChannel(); FileChannel outChannel = fos.getChannel(); // 獲取MapByteBuffer對象 MappedByteBuffer mapBuffer = inChannel.map(MapMode.READ_ONLY, 0, srcFile.length()); //字符集解碼器 Charset charset = Charset.forName("GBK"); outChannel.write(mapBuffer); CharsetDecoder decoder = charset.newDecoder(); CharBuffer charBuffer = decoder.decode(mapBuffer); System.out.println(charBuffer); }
通道能夠異步讀寫,異步讀寫表示通道執行讀寫操做時,也能作別的事情,解決線程阻塞。若是使用文件管道(FileChannel),建議用RandomAccessFile來建立管道,由於該類支持讀寫模式以及有大量處理文件的方法。post
public static void main(String[] args) throws Exception { File f = new File("nio-a.txt"); RandomAccessFile raf = new RandomAccessFile(f, "rw"); FileChannel channel = raf.getChannel(); MappedByteBuffer mapBuffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, f.length()); // raf.seek(f.length()); channel.position(f.length()); channel.write(mapBuffer); }
理解爲現實生活的編碼表對象
當使用NIO來獲取文件內容時,若是是文本數據,那麼須要進行轉碼,才能查看正確內容,這就須要解碼器。 若是要把字符數據寫入文件,須要將CharBuffer轉碼成ByteBuffer,這就須要編碼器。編碼
public static void main(String[] args) throws IOException { //匿名子對象實現FileVisitor接口 FileVisitor<Path> visitor = new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException { System.out.println("正在訪問" + path + "文件"); if(path.endsWith("NIODemo.java")){ System.out.println("恭喜您找到Java"); return FileVisitResult.CONTINUE; } return FileVisitResult.CONTINUE; } @Override public FileVisitResult preVisitDirectory(Path path, BasicFileAttributes attrs) throws IOException { System.out.println("準備訪問" + path + "文件"); return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path path, IOException exc) throws IOException { System.out.println("準備訪問" + path + "文件失敗"); System.out.println(exc.getMessage()); return FileVisitResult.CONTINUE; } }; //訪問文件樹 Files.walkFileTree(Paths.get("D:\\JavaSE"), visitor); }
以上線程
@Fzxey