OutputStream

OutputStream

OutputStream類是java開發中非常重要的類,是java IO中所有輸出流的父類。該類是一個抽象類,以便用子類對其的具體實現,這也是多態的一種體現。

java的OutputStream的類型


這一類別包括的類決定了我們的輸出往何處去:
一個位元組數組(但沒有String;假定我們可用位元組數組創建一個);
一個文件;或者一個“管道”。
除此以外,FilterOutputStream為“破壞器”類提供了一個基礎類,它將屬性或者有用的介面同輸出流連接起來。這將在以後討論。
表10.2 OutputStream的類型
ByteArray-OutputStreamCreates a buffer in memory. All the data that you send to the stream is placed in this buffer.Optional initial size of the buffer.
FilterOutputStream object to provide a useful interface.
File-OutputStreamFor sending information to a file.A String representing the file name, or a File or FileDescriptor object.
To designate the destination of your data. Connect it to a
Piped-OutputStreamAny information you write to this automatically ends up as input for the associated PipedInput-Stream. Implements the “piping” concept.PipedInputStream
To designate the destination of your data for multithreading. Connect it to a FilterOutputStream object to provide a useful interface.
Filter-OutputStream
Abstract class which is an interface for decorators that provide useful functionality to the other OutputStream classes. See Table
10-4.
See Table 10-4.
See Table 10-4.
類 功能 構建器參數/如何使用
ByteArrayOutputStream 在內存中創建一個緩衝區。我們發送給流的所有數據都會置入這個緩衝區。可選緩衝區的初始大小/用於指出數據的目的地。若將其同FilterOutputStream對象連接到一起,可提供一個有用的介面
FileOutputStream 將信息發給一個文件 用一個String代表文件名,或選用一個File或FileDescriptor對象/用於指出數據的目的地。
PipedOutputStream 我們寫給它的任何信息都會自動成為相關的PipedInputStream的輸出。實現了“管道化”的概念 PipedInputStream/為多線程處理指出自己數據的目的地/將其同FilterOutputStream對象連接到一起,便可提供一個有用的介面
FilterOutputStream 對作為破壞器介面使用的類進行抽象處理;那個破壞器為其他OutputStream類提供了有用的功能。參見表10.4

OutputStream的使用方法


根據寫數據的方式不同,OutputStream主要分成兩類;一類是寫給人看的,一類是供DataInputStream用的。雖然RandomAccessFile的數據格式同DataInputStream和DataOutputStream的相同,但它不屬於OutputStream的。

存儲和恢複數據

PrintWriter會對數據進行格式化,這樣人就能讀懂了。但是如果數據輸出之後,還要恢復出來供其它流用,那你就必須用DataOutputStream來寫數據,再用DataInputStream來讀數據了。當然,它們可以是任何流,不過我們這裡用的是一個經緩衝的文件。DataOutputStream和DataInputStream是面向byte的,因此這些流必須都是InputStream和OutputStream。
如果數據是用DataOutputStream寫的,那麼不管在哪個平台上,DataInputStream都能準確地把它還原出來。這一點真是太有用了,因為沒人知道誰在為平台專屬的數據操心。如果你在兩個平台上都用Java,那這個問題就根本不存在了。
用DataOutputStream寫String的時候,要想確保將來能用DataInputStream恢復出來,唯一的辦法就是使用UTF-8編碼,也就是像常式第5部分那樣,用writeUTF( )和readUTF( )。UTF-8是Unicode的一種變形。Unicode用兩個位元組來表示一個字元。但是,如果你處理的全部,或主要是ASCII字元(只有7位),那麼無論從存儲空間還是從帶寬上看,就都顯得太浪費了,所以UTF-8 用一個位元組表示ASCII字元,用兩或三個位元組表示非ASCII的字元。此外,字元串的長度信息存在(字元串)的頭兩個位元組里。writeUTF( )和readUTF( )用的是Java自己的UTF-8版本(JDK文檔里有關於這個字符集的完整講解,就在這兩個方法的文檔里),所以如果你要用一個Java程序讀取writeUTF( )寫的字元串的話,就必須進行一些特殊處理了。
有了writeUTF( )和readUTF( ),你就能放心地把String和其它數據混在一起交給DataOutputStream了,因為你知道String是以Unicode的形式存儲的,而且可以很方便地用DataOutputStream恢復出來。
writeDouble( )會往流里寫double,而它"影子"readDouble( )則負責把它恢復出來(其它數據也有類似的讀寫方法)。但是要想讓讀取方法能正常工作,你就必須知道流的各個位置上都放了些什麼數據。因為你完全可以把double讀成byte,char,或其它什麼東西。所以要麼以固定的格式寫文件,要麼在文件里提供額外的解釋信息,然後一邊讀數據一邊找數據。先提一下,對於複雜數據的存儲和恢復,對象的序列化可能會比較簡單。

讀寫隨機文件

正如我們前面所講的,如果不算它實現了DataInput和DataOutput介面,RandomAccessFile幾乎是完全獨立於其它I/O類庫之外的,所以它不能與InputStream和OutputStream合起來用。雖然把ByteArrayInputStream當作"隨機存取的元素(random-access element)"是一件很合情合理的事,但你只能用RandomAccessFile來打開文件。而且,你只能假定RandomAccessFile已經做過緩衝了,因為即便沒做你也無能為力。
構造函數的第二個參數的意思是:是以只讀("r") 還是讀寫("rw")方式打開RandomAccessFile。
RandomAccessFile的用法就像是DataInputStream和DataOutputStream的結合(因為它們的介面是等效的)。此外,你還能用seek( )在文件里上下移動,並進行修改。
隨著JDK 1.4的new I/O的問世,你該考慮一下是不是用"內存映射文件(memory-mapped file)"來代替RandomAccessFile了。