04.JavaIO流問題

瀟湘劍雨發表於2018-12-24

目錄介紹

  • 4.0.0.1 說一下Java IO裡面的常見類,位元組流,字元流、介面、實現類、方法阻塞?
  • 4.0.0.2 什麼是位元(Bit),什麼是位元組(Byte),什麼是字元(Char),它們長度是多少,各有什麼區別?
  • 4.0.0.3 字元流和位元組流有什麼區別?如何選擇位元組流或者字元流?什麼是緩衝區,有什麼作用?
  • 4.0.0.4 IO流中用到哪些模式?談一談IO流中用到的介面卡模式和裝飾者模式的作用優勢?
  • 4.0.0.5 說一下對NIO的理解?NIO和IO的主要區別?NIO和IO如何影響應用程式的設計?
  • 4.0.1.1 對位元組流進行大量的從硬碟讀取,要用那個流,為什麼?

好訊息

  • 部落格筆記大彙總【15年10月到至今】,包括Java基礎及深入知識點,Android技術部落格,Python學習筆記等等,還包括平時開發中遇到的bug彙總,當然也在工作之餘收集了大量的面試題,長期更新維護並且修正,持續完善……開源的檔案是markdown格式的!同時也開源了生活部落格,從12年起,積累共計500篇[近100萬字],將會陸續發表到網上,轉載請註明出處,謝謝!
  • 連結地址:https://github.com/yangchong2…
  • 如果覺得好,可以star一下,謝謝!當然也歡迎提出建議,萬事起於忽微,量變引起質變!所有部落格將陸續開源到GitHub!

4.0.0.1 說一下Java IO裡面的常見類,位元組流,字元流、介面、實現類、方法阻塞?

  • 輸出流和輸入流

    • 輸入流就是從外部檔案輸入到記憶體,輸出流主要是從記憶體輸出到檔案。
  • IO裡面常見的類

    • IO流中有很多類,IO流主要分為字元流和位元組流。字元流中有抽象類InputStream和OutputStream,它們的子類FileInputStream,FileOutputStream,BufferedOutputStream等。字元流BufferedReader和Writer等。都實現了Closeable, Flushable, Appendable這些介面。程式中的輸入輸出都是以流的形式儲存的,流中儲存的實際上全都是位元組檔案。
  • IO流中方法阻塞

    • java中的阻塞式方法是指在程式呼叫改方法時,必須等待輸入資料可用或者檢測到輸入結束或者丟擲異常,否則程式會一直停留在該語句上,不會執行下面的語句。比如read()和readLine()方法。
    • 技術部落格大總結

4.0.0.2 什麼是位元(Bit),什麼是位元組(Byte),什麼是字元(Char),它們長度是多少,各有什麼區別?

  • 什麼是位元(Bit)?

    • Bit最小的二進位制單位 ,是計算機的操作部分 取值0或者1
  • 什麼是位元組

    • Byte是計算機運算元據的最小單位由8位bit組成 取值(-128-127)
  • 什麼是字元

    • Char是使用者的可讀寫的最小單位,在Java裡面由16位bit組成 取值(0-65535)
  • 各有什麼區別

    • Bit 是最小單位 計算機 只能認識 0或者1

4.0.0.3 字元流和位元組流有什麼區別?如何選擇位元組流或者字元流?什麼是緩衝區,有什麼作用?

  • 字元流和位元組流區別

    • 把二進位制資料資料逐一輸出到某個裝置中,或者從某個裝置中逐一讀取一片二進位制資料,不管輸入輸出裝置是什麼,我們要用統一的方式來完成這些操作,用一種抽象的方式進行描述,這個抽象描述方式起名為IO流,對應的抽象類為OutputStream和InputStream ,不同的實現類就代表不同的輸入和輸出裝置,它們都是針對位元組進行操作的。
    • 在應用中,經常要完全是字元的一段文字輸出去或讀進來,用位元組流可以嗎?計算機中的一切最終都是二進位制的位元組形式存在。對於“中國”這些字元,首先要得到其對應的位元組,然後將位元組寫入到輸出流。讀取時,首先讀到的是位元組,可是我們要把它顯示為字元,我們需要將位元組轉換成字元。由於這樣的需求很廣泛,人家專門提供了字元流的包裝類。
    • 底層裝置永遠只接受位元組資料,有時候要寫字串到底層裝置,需要將字串轉成位元組再進行寫入。字元流是位元組流的包裝,字元流則是直接接受字串,它內部將串轉成位元組,再寫入底層裝置,這為我們向IO設別寫入或讀取字串提供了一點點方便。
    • 技術部落格大總結
    • 字元流和位元組流的使用非常相似,但是實際上位元組流的操作不會經過緩衝區(記憶體)而是直接操作文字本身的,而字元流的操作會先經過緩衝區(記憶體)然後通過緩衝區再操作檔案。
  • 如何選擇位元組流或者字元流?

    • 字元流是由Java虛擬機器將位元組轉化為2個位元組的Unicode字元為單位的字元而成的
    • 如果是音訊檔案、圖片、歌曲,就用位元組流好點(避免資料丟失)
    • 如果是關係到中文(文字)的,用字元流好點)
  • 什麼是緩衝區,有什麼作用?

    • 緩衝區就是一段特殊的記憶體區域,很多情況下當程式需要頻繁地操作一個資源(如檔案或資料庫)則效能會很低,所以為了提升效能就可以將一部分資料暫時讀寫到快取區,以後直接從此區域中讀寫資料即可,這樣就顯著提升了效能。
    • 對於 Java 字元流的操作都是在緩衝區操作的,所以如果我們想在字元流操作中主動將緩衝區重新整理到檔案則可以使用 flush() 方法操作。

4.0.0.4 IO流中用到哪些模式?談一談IO流中用到的介面卡模式和裝飾者模式的作用優勢?

  • IO流中用到哪些模式

    • 大概有裝飾者模式和介面卡模式!
    • 要知道裝飾者模式和介面卡模式的作用;其次,可以自己舉個例子把它的作用生動形象地講出來;最後,簡要說一下要完成這樣的功能需要什麼樣的條件。
  • 談一談IO流中用到的介面卡模式和裝飾者模式的作用優勢

    • 裝飾器模式:就是動態地給一個物件新增一些額外的職責(對於原有功能的擴充套件)。

      //把InputStreamReader裝飾成BufferedReader來成為具備緩衝能力的Reader。
      BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
      • 1.它必須持有一個被裝飾的物件(作為成員變數)。
      • 2.它必須擁有與被裝飾物件相同的介面(多型呼叫、擴充套件需要)。
      • 3.它可以給被裝飾物件新增額外的功能。
      • 比如,在io流中,FilterInputStream類就是裝飾角色,它實現了InputStream類的所有介面,並持有InputStream的物件例項的引用,BufferedInputStream是具體的裝飾器實現者,這個裝飾器類的作用就是使得InputStream讀取的資料儲存在記憶體中,而提高讀取的效能。
    • 介面卡模式:將一個類的介面轉換成客戶期望的另一個介面,讓原本不相容的介面可以合作無間。

      //把FileInputStream檔案位元組流適配成InputStreamReader字元流來操作檔案字串。
      FileInputStream fileInput = new FileInputStream(file); 
      InputStreamReader inputStreamReader = new InputStreamReader(fileInput);
      • 1.介面卡物件實現原有介面
      • 2.介面卡物件組合一個實現新介面的物件
      • 3.對介面卡原有介面方法的呼叫被委託給新介面的例項的特定方法(重寫舊介面方法來呼叫新介面功能。)
      • 比如,在io流中,InputStreamReader類繼承了Reader介面,但要建立它必須在建構函式中傳入一個InputStream的例項,InputStreamReader的作用也就是將InputStream適配到Reader。InputStreamReader實現了Reader介面,並且持有了InputStream的引用。這裡,介面卡就是InputStreamReader類,而源角色就是InputStream代表的例項物件,目標介面就是Reader類。
      • 介面卡模式主要在於將一個介面轉變成另一個介面,它的目的是通過改變介面來達到重複使用的目的;而裝飾器模式不是要改變被裝飾物件的介面,而是保持原有的介面,但是增強原有物件的功能,或改變原有物件的方法而提高效能。
  • 用到設計模式優勢

    • 裝飾者模式就是給一個物件增加一些新的功能,而且是動態的,要求裝飾物件和被裝飾物件實現同一個介面,裝飾物件持有被裝飾物件的例項(各種字元流間裝飾,各種位元組流間裝飾)。
    • 技術部落格大總結
    • 介面卡模式就是將某個類的介面轉換成我們期望的另一個介面表示,目的是消除由於介面不匹配所造成的類的相容性問題(字元流與位元組流間互相適配)。

4.0.0.5 說一下對NIO的理解?NIO和IO的主要區別?NIO和IO如何影響應用程式的設計?

  • 說一下對NIO的理解?

    • 傳統的IO流是阻塞式的,會一直監聽一個ServerSocket,在呼叫read等方法時,它會一直等到資料到來或者緩衝區已滿時才返回。呼叫accept也是一直阻塞到有客戶端連線才會返回。每個客戶端連線過來後,服務端都會啟動一個執行緒去處理該客戶端的請求。並且多執行緒處理多個連線。每個執行緒擁有自己的棧空間並且佔用一些CPU時間。每個執行緒遇到外部未準備好的時候,都會阻塞掉。阻塞的結果就是會帶來大量的程式上下文切換。
    • 對於NIO,它是非阻塞式,核心類:

      • 1.Buffer為所有的原始型別提供 (Buffer)快取支援。
      • 2.Charset字符集編碼解碼解決方案
      • 3.Channel一個新的原始I/O抽象,用於讀寫Buffer型別,通道可以認為是一種連線,可以是到特定裝置,程式或者是網路的連線。
  • NIO和IO的主要區別?

    • 主要區別

      IO     NIO
      面向流     面向緩衝
      阻塞IO     非阻塞IO
      無     選擇器
    • 面向流與面向緩衝

      • Java IO和NIO之間第一個最大的區別是,IO是面向流的,NIO是面向緩衝區的。JavaIO面向流意味著每次從流中讀一個或多個位元組,直至讀取所有位元組,它們沒有被快取在任何地方。此外,它不能前後移動流中的資料。如果需要前後移動從流中讀取的資料,需要先將它快取到一個緩衝區。JavaNIO的緩衝導向方法略有不同。資料讀取到一個它稍後處理的緩衝區,需要時可在緩衝區中前後移動。這就增加了處理過程中的靈活性。但是,還需要檢查是否該緩衝區中包含所有您需要處理的資料。而且,需確保當更多的資料讀入緩衝區時,不要覆蓋緩衝區裡尚未處理的資料。
    • 阻塞與非阻塞IO

      • Java IO的各種流是阻塞的。這意味著,當一個執行緒呼叫read()或write()時,該執行緒被阻塞,直到有一些資料被讀取,或資料完全寫入。該執行緒在此期間不能再幹任何事情了。JavaNIO的非阻塞模式,使一個執行緒從某通道傳送請求讀取資料,但是它僅能得到目前可用的資料,如果目前沒有資料可用時,就什麼都不會獲取,而不是保持執行緒阻塞,所以直至資料變的可以讀取之前,該執行緒可以繼續做其他的事情。非阻塞寫也是如此。一個執行緒請求寫入一些資料到某通道,但不需要等待它完全寫入,這個執行緒同時可以去做別的事情。執行緒通常將非阻塞IO的空閒時間用於在其它通道上執行IO操作,所以一個單獨的執行緒現在可以管理多個輸入和輸出通道(channel)。
    • 選擇器

      • Java NIO的選擇器允許一個單獨的執行緒來監視多個輸入通道,你可以註冊多個通道使用一個選擇器,然後使用一個單獨的執行緒來“選擇”通道:這些通道里已經有可以處理的輸入,或者選擇已準備寫入的通道。這種選擇機制,使得一個單獨的執行緒很容易來管理多個通道。
  • NIO和IO如何影響應用程式的設計?

    • 無論您選擇IO或NIO工具箱,可能會影響您應用程式設計的以下幾個方面:技術部落格大總結

      • 1.對NIO或IO類的API呼叫。
      • 2.資料處理。
      • 3.用來處理資料的執行緒數。
    • API呼叫

      • 當然,使用NIO的API呼叫時看起來與使用IO時有所不同,但這並不意外,因為並不是僅從一個InputStream逐位元組讀取,而是資料必須先讀入緩衝區再處理。
    • 資料處理

      • 使用純粹的NIO設計相較IO設計,資料處理也受到影響。在IO設計中,我們從InputStream或 Reader逐位元組讀取資料。
      • 請注意處理狀態由程式執行多久決定。換句話說,一旦reader.readLine()方法返回,你就知道肯定文字行就已讀完, readline()阻塞直到整行讀完,這就是原因。你也知道此行包含名稱;同樣,第二個readline()呼叫返回的時候,你知道這行包含年齡等。正如你可以看到,該處理程式僅在有新資料讀入時執行,並知道每步的資料是什麼。一旦正在執行的執行緒已處理過讀入的某些資料,該執行緒不會再回退資料(大多如此)。

4.0.1.1 對位元組流進行大量的從硬碟讀取,要用那個流,為什麼?

  • 對位元組流進行大量的從硬碟讀取,要用那個流,為什麼?

    • 因為明確說了是對位元組流的讀取,所以肯定是inputstream或者他的子類,又因為要大量讀取,肯定要考慮到高效的問題,自然想到緩衝流。技術部落格大總結
    • 用BufferedInputStream,原因:BufferedInputStream是InputStream的緩衝流,使用它可以防止每次讀取資料時進行實際的寫操作,代表著使用緩衝區。不帶緩衝的操作,每讀一個位元組就要寫入一個位元組,由於涉及磁碟的IO操作相比記憶體的操作要慢很多,所以不帶緩衝的流效率很低。帶緩衝的流,可以一次讀很多位元組,但不向磁碟中寫入,只是先放到記憶體裡。等湊夠了緩衝區大小的時候一次性寫入磁碟,這種方式可以減少磁碟操作次數,速度就會提高很多!並且也可以減少對磁碟的損傷。

其他介紹

01.關於部落格彙總連結

02.關於我的部落格

相關文章