NIO详解
目錄
- NIO
- 前言
- IO與NIO的區(qū)別
- Buffer(緩沖區(qū))
- Channel(通道)
- Charset(字符集)
- NIO遍歷文件
NIO
前言
NIO即New IO,這個庫是在JDK1.4中才引入的。NIO和IO有相同的作用和目的,但實現(xiàn)方式不同,NIO主要用到的是塊,所以NIO的效率要比IO高很多。在Java API中提供了兩套NIO,一套是針對標準輸入輸出NIO,另一套就是網(wǎng)絡編程NIO。
IO與NIO的區(qū)別
- IO流是面向流的,屬于阻塞IO,沒有選擇器。
- NIO流是面向塊(緩沖區(qū)),屬于非阻塞IO有選擇器。
其中最大的區(qū)別就是一個面向流,一個面向緩沖區(qū)。- 面向流:IO流每次讀取一個字節(jié)或者多個,直到讀完為止。不能對流中的數(shù)據(jù)進行操作。
- 面向緩沖區(qū):NIO流是將數(shù)據(jù)放到一個緩沖區(qū),需要時可以對緩沖區(qū)中的數(shù)據(jù)進行操作,這樣就可以更加靈活的操作數(shù)據(jù)了。(就好像IO流是一根水管,而NIO是一個運水車)
Buffer(緩沖區(qū))
Buffer是一個抽象類;
子類有:ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer
核心類(常用類):ByteBuffer和CharBuffer 其中ByteBuffer有一個子類MappedByteBuffer(MappedByteBuffer類能夠?qū)⑽募苯佑成涞絻?nèi)存中,那么這樣我們就可以像訪問內(nèi)存一樣訪問文件,非常方便)
創(chuàng)建Buffer
因為Buffer都是抽象類,無法直接實例化。創(chuàng)建緩沖區(qū)要調(diào)用XxxBuffer allocate(int capacity),XxxBuffer allocateDirect(int capacity),參數(shù)是緩沖區(qū)容量。
eg:獲取ByteBuffer
static ByteBuffer allocate(int capacity)
分配一個新的字節(jié)緩沖區(qū)(普通Buffer)
static ByteBuffer allocateDirect(int capacity)
分配新的直接字節(jié)緩沖區(qū)(直接Buffer)
二者的區(qū)別:
Buffer參數(shù)
- capacity(容量):緩沖區(qū)的容量,不可以為負數(shù),一旦創(chuàng)建了就不能夠改變
- limit(界限):是緩沖區(qū)讀寫數(shù)據(jù)的終止點,limit之后的區(qū)域無法訪問
- position(起始指針):是緩沖區(qū)讀寫數(shù)據(jù)的起始點,初始值為0。position隨著數(shù)據(jù)的加入而改變,例如讀取2個數(shù)據(jù)到Buffer中,則position = 2
- mark(標記):該索引能夠用于下次讀取或者寫入,mark在0~position之間,設置該值就會把position移動到mark處
Buffer方法
- flip():讀取模式;確定緩沖區(qū)數(shù)據(jù)的起始點和終止點,為輸出數(shù)據(jù)做準備(即寫入通道), 將limit的值改為postion的值,同時將postion歸0
- 特點: 就是為下一次數(shù)據(jù)的讀取做好準備
- clear():寫入模式;緩沖區(qū)初始化,準備再次接收新數(shù)據(jù)到緩沖區(qū),將limit改為capacity的值,同時將postion歸0
- 特點: 就是為下一次數(shù)據(jù)的寫入做好準備
- get()和put():獲取元素和存放元素。使用clear()之后,無法直接使用get()獲取元素,需要使用get(int index)根據(jù)索引值來獲取相應元素
- hasRemaining():判斷postion到limit之間是否還有元素。
Channel(通道)
Channel原理類似于傳統(tǒng)的流對象,區(qū)別在于:
1.Channel能夠?qū)⒅付ǖ牟糠只蛘呷课募成涞絻?nèi)存中
2.程序如果想要讀取Channel中的數(shù)據(jù),不能夠直接讀寫,必須經(jīng)過Buffer
簡單來說:Channel通過Buffer(緩沖區(qū))進行讀寫操作。read()表示讀取通道數(shù)據(jù)到緩沖區(qū),write()表示把緩沖區(qū)數(shù)據(jù)寫入到通道。
Channel實現(xiàn)類
- FileChannel 和文件相關的通道
- DatagramChannel 和UDP協(xié)議傳輸數(shù)據(jù)相關的通道
- SocketChannel 和TCP協(xié)議相關的數(shù)據(jù)傳輸通道
- ServerSocket 和TCP協(xié)議相關的數(shù)據(jù)傳輸通道
- Pipe.SinkChannel、Pipe.SourceChannel //線程通信管道傳輸數(shù)據(jù)
Channel常用方法
- read() : 將Channel中的數(shù)據(jù)讀取到Buffer中
- write() : 向Buffer中寫入數(shù)據(jù)
- map(): 將channel中的數(shù)據(jù)全部或者部分映射到Buffer中(MappedByteBuffer,本質(zhì)也是一個ByteBuffer),map()方法參數(shù)(讀寫模式,映射起始位置,數(shù)據(jù)長度)。
- inChannel.map(mode, position, size)
- MappedByteBuffer mappBuffer = inChannel.map(MapMode.READ_ONLY, 0, srcFile.length());
通道可以異步讀寫,異步讀寫表示通道執(zhí)行讀寫操作時,也能做別的事情,解決線程阻塞。如果使用文件管道(FileChannel),建議用RandomAccessFile來創(chuàng)建管道,因為該類支持讀寫模式以及有大量處理文件的方法。
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);}Charset(字符集)
理解為現(xiàn)實生活的編碼表對象
當使用NIO來獲取文件內(nèi)容時,如果是文本數(shù)據(jù),那么需要進行轉(zhuǎn)碼,才能查看正確內(nèi)容,這就需要解碼器。 如果要把字符數(shù)據(jù)寫入文件,需要將CharBuffer轉(zhuǎn)碼成ByteBuffer,這就需要編碼器。
- 包含了字節(jié)和 Unicode 字符之間轉(zhuǎn)換的 charset,還定義了用于創(chuàng)建解碼器和編碼器以及獲取與 charset 關聯(lián)的各種方法
- CharsetDecoder(解碼器):把字節(jié)轉(zhuǎn)成字符,例如查看文本數(shù)據(jù),需要轉(zhuǎn)成字符才能查看,如果是字節(jié),就看不懂了。
- CharsetEncoder(編碼器):把字符轉(zhuǎn)成字節(jié),才能被計算機理解。 因為字節(jié)是計算機最小的存儲單位,所以Channel的IO操作都與ByteBuffer有關
- 解碼器和編碼器都不能直接創(chuàng)建,需要一個Charset對象來創(chuàng)建對應的解碼器和編碼器。
Charset常用方法
- forName():根據(jù)傳入的字符集獲得對應的字符集對象。
- defaultCharset():獲得當前使用的默認字符集。
- availableCharsets():獲得所有有效的字符集。
NIO遍歷文件
public static void main(String[] args) throws IOException {//匿名子對象實現(xiàn)FileVisitor接口FileVisitor<Path> visitor = new SimpleFileVisitor<Path>() {@Overridepublic 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;}@Overridepublic FileVisitResult preVisitDirectory(Path path, BasicFileAttributes attrs) throws IOException {System.out.println("準備訪問" + path + "文件");return FileVisitResult.CONTINUE;}@Overridepublic 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
轉(zhuǎn)載于:https://www.cnblogs.com/fzxey/p/10828465.html
總結
- 上一篇: ivew 双向绑定时间控件
- 下一篇: 软件开发冲刺3