1. 用JAVA的IO流里的哪個類效率最高
Java中IO流分成兩大類,
一種是輸入流,所有的輸入流都直接或間接繼承自InputStream抽象類,輸入流作為數據的來源,我們可以通過輸入流的read方法讀取位元組數據;
另一種是輸出流,所有的輸出流都直接或間接繼承自OutputStream抽象類,輸出流接收數據,可以通過write方法寫入位元組數據。
Java的IO流類中,大部分的輸入流和輸出流都是成對存在的,即如果存在XXXInputStream,那麼就存在XXXOutputStream,反之亦然。SequenceInputStream和StringBufferInputStream是特例,沒有對應的SequenceOutputStream類和StringBufferOutputStream類,許多IO操作都可能會拋出IOException異常,比如read、write、close操作。
以下是Java的IO流中常見的輸入流,由於每個輸入流都有其對應的輸出流,所以此處就不再列出輸出流的繼承結構圖。
1、ByteArrayInputStream & ByteArrayOutputStream:
ByteArrayInputStream構造函數中需要傳入一個byte數組作為數據源,當執行read操作時,就會從該數組中讀取數據,正如其名,是一種基於位元組數組實現的一種簡單輸入流,顯而易見的是,如果在構造函數中傳入了null作為位元組數據,那麼在執行read操作時就會出現NullPointerException異常,但是在構造函數初始化階段不會拋出異常;與之相對應的是ByteArrayOutputStream,其內部也有一個位元組數組用於存儲write操作時寫入的數據,在構造函數中可以傳入一個size指定其內部的byte數組的大小,如果不指定,那麼默認它會將byte數組初始化為32位元組,當持續通過write向ByteArrayOutputStream中寫入數據時,如果其內部的byte數組的剩餘空間不能夠存儲需要寫入的數據,那麼那麼它會通過調用內部的ensureCapacity
方法對其內部維護的byte數組進行擴容以存儲所有要寫入的數據,所以不必擔心其內部的byte數組太小導致的IndexOutOfBoundsException之類的異常。
2、FileInputStream & FileOutputStream
FileInputStream 能夠將文件作為數據源,讀取文件中的流,通過File對象或文件路徑等初始化,在其構造函數中,如果傳入的File對象(或與其相對應的文件路徑所表示的File對象)不存在或是一個目錄而不是文件或者由於其他原因無法打開讀取數據,都會導致在初始化階段導致拋出FileNotFoundException異常;與FileInputStream 相對應的是FileOutputStream,可以通過FileOutputStream向文件中寫入數據,也需要通過File對象或文件路徑對其初始化,如同FileInputStream ,如果傳入的File對象(或與其相對應的文件路徑所表示的File對象)是一個目錄而不是文件或者由於其他原因無法創建該文件寫入數據,都會導致在初始化階段拋出FileNotFoundException異常。
3、PipedInputStream & PipedOutputStream
PipedInputStream和PipedOutputStream一般是結合使用的,這兩個類用於在兩個線程間進行管道通信,一般在一個線程中執行PipedOutputStream 的write操作,而在另一個線程中執行PipedInputStream的read操作。可以在構造函數中傳入相關的流將PipedInputStream 和PipedOutputStream 綁定起來,也可以通過二者的connect方法將二者綁定起來,一旦二者進進行了綁定,那麼PipedInputStream的read方法就會自動讀取PipedOutputStream寫入的數據。PipedInputStream的read操作是阻塞式的,當執行PipedOutputStream的write操作時,PipedInputStream會在另一個線程中自動讀取PipedOutputStream寫入的內容,如果PipedOutputStream一直沒有執行write操作寫入數據,那麼PipedInputStream的read方法會一直阻塞PipedInputStream的read方法所運行的線程直至讀到數據。單獨使用PipedInputStream或單獨使用PipedOutputStream時沒有任何意義的,必須將二者通過connect方法(或在構造函數中傳入對應的流)進行連接綁定,如果單獨使用其中的某一個類,就會觸發IOException: Pipe Not Connected.
4、ObjectInputStream & ObjectOutputStream
ObjectOutputStream具有一系列writeXXX方法,在其構造函數中可以摻入一個OutputStream,可以方便的向指定的輸出流中寫入基本類型數據以及String,比如writeBoolean、writeChar、writeInt、writeLong、writeFloat、writeDouble、writeCharts、writeUTF等,除此之外,ObjectOutputStream還具有writeObject方法。writeObject方法中傳入的類型必須實現了Serializable介面,從而在執行writeObject操作時將對象進行序列化成流,並將其寫入指定的輸出流中。與ObjectOutputStream相對應的是ObjectInputStream,ObjectInputStream有與OutputStream中的writeXXX系列方法完全對應的readXXX系列方法,專門用於讀取OutputStream通過writeXXX寫入的數據。
5、SequenceInputStream
SequenceInputStream 主要是將兩個(或多個)InputStream在邏輯上合並為一個InputStream,比如在構造函數中傳入兩個InputStream,分別為in1和in2,那麼SequenceInputStream在讀取操作時會先讀取in1,如果in1讀取完畢,就會接著讀取in2。在我們理解了SequenceInputStream 的作用是將兩個輸入流合並為一個輸入流之後,我們就能理解為什麼不存在對應的SequenceOutputStream 類了,因為將一個輸出流拆分為多個輸出流是沒有意義的。
6、StringBufferInputStream
StringBufferInputStream允許通過在構造函數中傳入字元串以讀取位元組,在讀取時內部主要調用了String的charAt方法。與SequenceInputStream類似,StringBufferInputStream也沒有對應的OutputStream,即不存在StringBufferOutputStream類。Java沒有設計StringBufferOutputStream類的理由也很簡單,我們假設StringBufferOutputStream存在,那麼StringBufferOutputStream應該是內部通過執行write操作寫入數據更新其內部的String對象,比如有可能是通過StringBuilder來實現,但是這樣做毫無意義,因為一旦我們String的構造函數中可以直接傳入位元組數組構建字元串,簡單明了,所以設計StringBufferOutputStream就沒有太大的必要了。StringBufferInputStream這個類本身存在一點問題,它不能很好地將字元數組轉換為位元組數組,所以該類被Java標記為廢棄的(Deprecated),其官方推薦使用StringReader作為代替。