java的OutputStream的類型
這一類別包括的類決定了我們的輸出往何處去:
一個位元組數組(但沒有String;假定我們可用位元組數組創建一個);
一個檔案;或者一個“管道”。
除此以外,FilterOutputStream為“破壞器”類提供了一個基礎類,它將屬性或者有用的接口同輸出流連線起來。這將在以後討論。
表10.2 OutputStream的類型
| | |
| | |
ByteArray-OutputStream | Creates a buffer in memory. All the data that you send to the stream is placed in this buffer. | Optional initial size of the buffer. |
To designate the destination of your data. Connect it to a FilterOutputStream object to provide a useful interface. | | |
File-OutputStream | For 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 FilterOutputStream object to provide a useful interface. | | |
Piped-OutputStream | Any 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了。