Java: I/O(1/3)字節流與字符流的縱向與橫向比較

Summary 總述

java.io包中的類很是繁多,但其實只要歸成4類:InputStream & OutputStreamReader & Writer,因爲功能和命名上都至關接近,所以只要掌握了其中一種,將會很容易理解其餘3種。java

橫向歸類:InputStream & OutputStream(字節流)、Reader & Writer(字符流).
縱向歸類:InputStream做爲父類,其子類的角色和做用,並以此觸類旁通。api

字節流

字節(byte)是計算機中基本數據單位,一切的計算機數據(或「文件」)都是由或多或少的字節組成,所以使用字節流,理論上能夠處理一切計算機數據(文件),包括圖像、音頻、文本等。數組

然而對於文本數據,因爲存在編碼問題比較麻煩,因此交由字符流處理。oracle

字符流

1char=2byte,字符(char)的表示範圍(2^16)是字節(byte)表示範圍(2^8)的2^8=256倍。專門用於處理文本數據。dom

歷史

字節流在Java的第一版(jdk 1.0)已經存在,字符流在jdk 1.1中加入,以替代字節流中處理字符的功能。性能

裝飾者模式

私覺得,提到Java I/O的話,不能不提裝飾者模式ui

裝飾者模式就是在一個主體(被裝飾者)的外部使用裝飾類來進行裝飾,對主體的行爲根據不一樣的裝飾者類進行不一樣的修改。單個的裝飾類自根據自身特色對主體的行爲進行部分改進,所以能夠組合多個裝飾類來對主體進行修改(在代碼中表現爲多層裝飾類的嵌套)。編碼

Java的I/O類設計應用了裝飾者模式。單個的流對象主體,例如InputStream的直接子類(Direct Subclasses)中,分別面向文件FileInputStream、內存ByteArrayInputStream、線程PipedInputStream,而InputStream的另外一個直接子類FileterInputStream爲裝飾類(的父類),分別定義了各類具體的裝飾類(如BufferedInputStreamDataInputStream等)。線程

如圖: Alt text設計

從代碼的角度來看:DataInputStreamBufferedInputStream爲裝飾者,FileInputStream爲主體(被裝飾者)

InputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(new File(src))));

裝飾者模式從抽象的角度來講很容易理解,然而也存在一個很明顯的缺點:裝飾類過多。所以咱們能看到java.io包中那麼多的類。若是沒有理解裝飾者模式,即便有必定經驗的Java developer也會感到混亂。

結論

  • 處理非文本數據使用字節流;
  • 處理具體的文本數據使用字符流;

例如對於文件複製這樣的操做來講,即便是文本文件的複製,咱們對其具體的內容是什麼並不關心,所以能夠直接使用字節流。但當咱們要從一個文本文件中讀取內容,咱們關心其具體的內容,因此使用字符流。


Description 詳細內容

篇幅所限,只列出經常使用的類,其他部分可參考Java API手冊

繼承關係圖

Alt text

字節流的繼承關係

OutputStream

  • OutputStream
    • ByteArrayOutputSteam:將數據輸出到字節數組(byte array)中,也就是內存,不用生成文件;
    • FileOutputStream:將數據輸出到具體的文件;
    • PipedOutputStream:將數據輸出到線程,即經過與PipedInputStream聯合使用,將數據在不一樣的線程之間傳遞;
    • FilterOutputStream:裝飾類的父類
      • BufferedOutputStream:使用了緩衝區,調用flush()纔會清空緩衝區將數據寫入文件。與普通OutputStream相比,因爲不用頻繁地與文件進行I/O數據傳輸(內存與磁盤之間,這將消耗大部分性能),而是在每次調用flush()時一次性地將一塊數據在內存與磁盤中傳輸,所以會性能將獲得提高(有NIO的影子);
      • DataOutputStream:用於方便地傳輸基礎類型的數據,所以除了傳統的write()外,還有一堆writeInt()、writeDouble、writeBoolean()等;
      • PrintStream:InputStream原本是適合用於非文本的二進制文件(如圖片、聲音文件等),而PrintStream則是在字節流中專門用於打印文本內容;

InputStream

  • InputStream
    • ByteArrayInputStream:從內存中讀取數據;
    • FileInputStream:從文件中讀取數據;
    • PipedInputStream:從一個線程中讀取數據,從另外一個線程中輸出(PipedOutputStream),同一線程下使用者兩個對象可能會形成線程死鎖;
    • SequenceInputStream:將兩個InputStream合併成一個;
    • FilterInputStream:裝飾類的父類;
      • BufferedInputStream:使用了緩衝區,參考BufferedOutputStream
      • DataInputStream:方便地讀取基本類型的數據,所以除了基礎的read()外,還有一堆readChar()、readDouble()、readInt()等;

字符流的繼承關係

Writer

  • BufferedWriter:緩衝區;
  • CharArrayWriter:面向內存;
  • PipedWriter:面向線程;
  • PrintWriter:方便輸出,特別是按格式輸出printf();
  • StringWriter:使用StringBuilder來存放內容;
  • OutputStreamWriter:用於字符流與字節流之間的轉換;
    • FileWriter:面向文件
  • FilterWriter:裝飾類

Reader

  • BufferedReader:緩衝區;
  • CharArrayReader:面向內存;
  • PipedReader:面向線程;
  • InputStreamReader:用於字符流與字節流之間的轉換;
    • FileReader:面向文件
  • FilterReader

Others 其餘

本篇做爲Java I/O系列之一,只分析了字節流和字符流。其餘Java I/O內容如File、RandomAccessFile、System類的I/O支持和重定向、字符編碼、文件壓縮、對象序列化和Scanner等內容會在(2/3)中發表。

NIO部分打算在(3/3)中發表。

相關文章
相關標籤/搜索