JAVA NIO編程入門(一)

1、前言

筆者以前接觸的NIO編程比較少,因此對這一塊的基礎也比較弱,NIO做爲java編程中一個重要的模塊,不能很好的掌握它,感受本身在java方面就掌握的不夠,因此,接下來,筆者會學習NIO編程,因此,該系列文章不會涉及到很深源碼解析,純粹的是學習課程,也能夠理解爲筆者的筆記,記錄學習NIO的過程,同時也但願這類文章能夠對一樣想掌握NIO編程的你有幫助。html

2、什麼是NIO?

Java NIO(New IO)是一個能夠替代標準Java IO API的IO API(從Java 1.4開始),Java NIO提供了與標準IO不一樣的IO工做方式。NIO能夠理解爲非阻塞IO,傳統的IO的read和write只能阻塞執行,線程在讀寫IO期間不能幹其餘事情,好比調用socket.read()時,若是服務器一直沒有數據傳輸過來,線程就一直阻塞,而NIO中能夠配置socket爲非阻塞模式。java

3、IO和NIO的區別

  • IO是面向字節流和字符流的,而NIO是面向緩衝區的。
  • IO是阻塞模式的,NIO是非阻塞模式的
  • NIO新增了選擇器的概念,能夠經過選擇器監聽多個通道。

4、NIO相關概念

Channel(通道)編程

Java NIO的通道相似流,但又有些不一樣:bash

既能夠從通道中讀取數據,又能夠寫數據到通道。但流的讀寫一般是單向的。 通道能夠異步地讀寫。服務器

通道中的數據老是要先讀到一個Buffer,或者老是要從一個Buffer中寫入。網絡

Channel的實現app

這些是Java NIO中最重要的通道的實現:dom

  • FileChannel: 從文件中讀寫數據。異步

  • DatagramChannel : 能經過UDP讀寫網絡中的數據。socket

  • SocketChannel: 能經過TCP讀寫網絡中的數據。

  • ServerSocketChannel :能夠監聽新進來的TCP鏈接,像Web服務器那樣。對每個新進來的鏈接都會建立一個SocketChannel。

Buffer(緩衝區)

緩衝區本質上是一塊能夠寫入數據,而後能夠從中讀取數據的內存。這塊內存被包裝成NIO Buffer對象,並提供了一組方法,用來方便的訪問該塊內存。

Buffer(緩衝區)的主要屬性

屬性 功能
capacity 容量
position 緩衝區當前位置指針,最大可爲capacity – 1
limit 緩衝區最大讀取和寫入限制

buffer屬性示意圖:

上圖展現了寫模式和讀模式下,以上屬性的示意圖,寫模式下,limit和capacity是同樣的,這表示你能寫入的最大容量數據,讀模式下,limit會和position同樣,表示你能讀到寫入的所有數據。

Buffer(緩衝區)的主要分類

  • ByteBuffer
  • MappedByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer

其實以上基本上爲了接收不一樣的數據類型而對應的,只有一個特殊的MappedByteBuffer,本次先不學習它,後續再去了解它。

5、實戰

咱們主要以理解上面介紹的概念爲目的實現一個簡單的NIO編程,讀取文件夾內的文件,而後輸出到控制檯。

public static  void testNio(){
        try {
            RandomAccessFile rdf=new RandomAccessFile("E:\\nio\\niotest.txt","rw");
            //利用channel中的FileChannel來實現文件的讀取
            FileChannel inChannel=  rdf.getChannel(); 
            //設置緩衝區容量爲10
            ByteBuffer buf=  ByteBuffer.allocate(10);
            //從通道中讀取數據到緩衝區,返回讀取的字節數量
            int byteRead=inChannel.read(buf);
            //數量爲-1表示讀取完畢。
            while (byteRead!=-1){
                //切換模式爲讀模式,其實就是把postion位置設置爲0,能夠從0開始讀取
                buf.flip();
                //若是緩衝區還有數據
                while (buf.hasRemaining()){
                    //輸出一個字符
                    System.out.print((char) buf.get());
                }
                //數據讀完後清空緩衝區
                buf.clear();
                //繼續把通道內剩餘數據寫入緩衝區
                byteRead = inChannel.read(buf);
            }
            //關閉通道
            rdf.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
複製代碼

我在磁盤中niotest.txt的內容是hello world,咱們看看運行結果是否是hello world。

結果和預期同樣,咱們完成了NIO編程輸出磁盤文件內容,其實上面代碼中,我第一印象有疑問的地方就是 buf.flip(),其餘只要用過IO的應該都能理解,既然不能理解咱們就先調試下,註釋掉該段內容,看看輸出結果如何。

註釋掉buf.flip()後,輸出結果果然不對了,那到底是爲啥呢?

上圖是第一個循環,咱們能夠看到緩衝區的position=10,limit=10,cap=10。調用 buf.hasRemaining()爲false,因此buffer第一次沒有輸出任何東西。看看第二次循環

其實這整個循環能夠解析步驟以下:

  • buffer讀取了10字節內容,內容就是:hello worl。

  • buf.hasRemaining() 判斷爲false,直接清空buffer(直接把position復位爲0,能夠直接覆蓋內容),讀取剩下內容。

  • 最後只剩下一個字符 d 讀取,這個時候讀取完後,buffer內容以下:dello worl。

  • 最後輸出由於從postion=1位置輸出,因此輸出:ello worl。

根據以上解析,咱們發現註釋了buf.flip()後,position位置寫入是什麼位置,讀出就是什麼位置,因此,該方法應該就是把position賦值爲0,從開始讀取。解讀源碼也證明了個人猜測,源碼以下:

public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;
    }
複製代碼

參考

JAVA NIO

推薦閱讀

Java鎖之ReentrantLock(一)

Java鎖之ReentrantLock(二)

Java鎖之ReentrantReadWriteLock

相關文章
相關標籤/搜索