InputStream和OutputStream及相關(guān)知識匯總

最近幫學(xué)姐寫爬蟲的時候遇到奇怪的問題,同樣的程序在Mac上可以正常運(yùn)行而在Windows上返回結(jié)果錯誤凑保,最后經(jīng)排查發(fā)現(xiàn)是Linux與Windows的默認(rèn)編碼方式不同,而自己的程序沒有設(shè)置編碼方式自動采用了默認(rèn)的編碼方式须尚,所以導(dǎo)致錯誤發(fā)生动分。之后嘗試了多種編碼方式均告失敗,最后發(fā)現(xiàn)是由于自己對輸入輸出流的認(rèn)識不到位捷犹,沒有正確使用的原因弛饭,故進(jìn)行整理學(xué)習(xí)。

首先認(rèn)識一下字節(jié)流與字符流萍歉。程序中的輸入輸出都是通過流的形式保存的侣颂,流中保存的全是字節(jié)文件。根據(jù)處理數(shù)據(jù)類型不同可以分為字節(jié)流和字符流枪孩。字節(jié)流是字符流的基礎(chǔ)憔晒。

字節(jié)流:字節(jié)流處理單元為一個字節(jié),操作字節(jié)和字節(jié)數(shù)組蔑舞。如果是音頻拒担、圖片等建議用字節(jié)流。
字符流:字符流處理單元為兩個字節(jié)的UNICODE字符斗幼,操作字符家澎蛛、字符數(shù)組和字符串,對多國語言支持性較好蜕窿,如果是文本建議用字符流谋逻。

基于字節(jié)流的Stream:通常以O(shè)utputStream和InputStream結(jié)尾呆馁,DataOutputStream、DataInputStream毁兆、FileOutputStream……
**基于字符流的Stream:通常以Writer和Reader結(jié)尾浙滤,PrintWriter、FileWriter气堕、FileReader纺腊、StringWriter……

可以發(fā)現(xiàn)絕大部份流都是成對出現(xiàn)的,包括輸入流和輸出流茎芭∫灸ぃ可以這樣理解輸入輸出流
輸入流(InputStream和Reader)可以看作一個出水的水龍頭,具有流出水流的功能梅桩,即向程序產(chǎn)生數(shù)據(jù)的功能壹粟,read便相當(dāng)于打開開關(guān),之后便會流出水流(數(shù)據(jù))宿百。
輸出流(OutputStream和Writer)可以看作一個進(jìn)水的水龍頭趁仙,具有儲存水流的功能,即接收程序產(chǎn)生的數(shù)據(jù)垦页,write后也相當(dāng)于打開開關(guān)雀费,水流(數(shù)據(jù))流進(jìn)進(jìn)水水龍頭。
介紹完了基本概念痊焊,現(xiàn)在來看一下基本用法盏袄。

InputStream
從流中讀取數(shù)據(jù)
public abstract int read() throws IOException 從輸入流中讀取下一字節(jié)。返回0到255范圍內(nèi)的int字節(jié)值宋光。如果因為已經(jīng)到達(dá)流末尾而沒有可用的字節(jié)貌矿,則返回-1炭菌。
public int read(byte[] b) throws IOException 從輸入流中讀取一定數(shù)量的字節(jié)罪佳,并將其存儲在緩沖區(qū)數(shù)組b中。以整數(shù)形式返回實際讀取的字節(jié)數(shù)黑低。等同于read(byte[]赘艳,int,int)
public int read(byte[] b, int off, int len) throws IOException 將輸入流中最多l(xiāng)en個數(shù)據(jù)字節(jié)讀入byte數(shù)組克握。嘗試讀取len個字節(jié)蕾管,但讀取的字節(jié)也可能小于該值。將讀取的第一個字節(jié)存儲在元素b[off]到b[off+k-1]的元素中菩暗,以此類推掰曾。
public long skip(long n) throws IOException 跳過和丟棄此輸入流中數(shù)據(jù)的 n 個字節(jié)。出于各種原因停团,skip 方法結(jié)束時跳過的字節(jié)數(shù)可能小于該數(shù)旷坦,也可能為 0掏熬。導(dǎo)致這種情況的原因很多,跳過 n 個字節(jié)之前已到達(dá)文件末尾只是其中一種可能秒梅。返回跳過的實際字節(jié)數(shù)旗芬。如果 n 為負(fù),則不跳過任何字節(jié)捆蜀。此類的 skip 方法創(chuàng)建一個 byte 數(shù)組疮丛,然后重復(fù)將字節(jié)讀入其中,直到讀夠 n 個字節(jié)或已到達(dá)流末尾為止辆它。建議子類提供此方法更為有效的實現(xiàn)誊薄。例如,可依賴搜索能力的實現(xiàn)锰茉。
public int available() throws IOException 返回此輸入流下一個方法調(diào)用可以不受阻塞地從此輸入流讀认疚荨(或跳過)的估計字節(jié)數(shù)(流中尚未被讀取的字節(jié)數(shù))。下一個調(diào)用可能是同一個線程洞辣,也可能是另一個線程咐刨。一次讀取或跳過此估計數(shù)個字節(jié)不會受阻塞,但讀取或跳過的字節(jié)數(shù)可能小于該數(shù)扬霜。注意定鸟,有些 InputStream 的實現(xiàn)將返回流中的字節(jié)總數(shù),但也有很多實現(xiàn)不會這樣做著瓶。試圖使用此方法的返回值分配緩沖區(qū)联予,以保存此流所有數(shù)據(jù)的做法是不正確的。如果已經(jīng)調(diào)用 close() 方法關(guān)閉了此輸入流材原,那么此方法的子類實現(xiàn)可以選擇拋出 IOException沸久。類 InputStream 的 available 方法總是返回 0。此方法應(yīng)該由子類重寫余蟹。
關(guān)閉流
public void close() throws IOException 關(guān)閉輸入流并釋放與該流關(guān)聯(lián)的所有系統(tǒng)資源
使用輸入流中的標(biāo)記
public void mark(int readlimit) 在此輸入流中標(biāo)記當(dāng)前位置卷胯。對 reset 方法的后續(xù)調(diào)用會在最后標(biāo)記的位置重新定位此流,以便后續(xù)讀取重新讀取相同的字節(jié)威酒。readlimit 參數(shù)表示讀取readmit個字節(jié)數(shù)后標(biāo)記失效窑睁。
public void reset() throws IOException 將讀指針重新指向mark方法記錄的位置。
public boolean markSupported() 測試此輸入流是否支持mark()和reset()方法葵孤。
OutputStream
輸出數(shù)據(jù)
public abstract void write(int b) throws IOException 將指定的字節(jié)寫入輸出流担钮。write 的常規(guī)協(xié)定是:向輸出流寫入一個字節(jié)。要寫入的字節(jié)是參數(shù) b 的八個低位尤仍。b 的 24 個高位將被忽略箫津。
public void write(byte[] b) throws IOException 將b.length個字節(jié)從指定的byte數(shù)組寫入此輸出流。與write(b, 0, b.length)等同
public void write(byte[] b, int off, int len) throws IOException 將指定數(shù)組中從偏移量off開始的len個字節(jié)寫入此輸出流。
刷新流
public void flush() throws IOException 刷新此輸出流并強(qiáng)制寫出所有緩沖的字節(jié)苏遥。如果此流的預(yù)期目標(biāo)是由基礎(chǔ)操作系統(tǒng)提供的一個抽象(如一個文件)送挑,則刷新此流只能保證將以前寫入到流的字節(jié)傳遞給操作系統(tǒng)進(jìn)行寫入,但不保證能將這些字節(jié)實際寫入到物理設(shè)備(如磁盤驅(qū)動器)暖眼。
關(guān)閉流
public void close() throws IOException 關(guān)閉此輸出流并釋放與此流有關(guān)的所有系統(tǒng)資源

通過輸入輸出流復(fù)制圖片的例子:

public class Test {
    public static void main(String[] args) throws IOException{
        long startTime = System.currentTimeMillis();
        InputStream is = new FileInputStream(new File("/Users/zhaokang/Desktop/1.jpg"));
        OutputStream os = new FileOutputStream(new File("/Users/zhaokang/Desktop/2.jpg"));
        int i = 0;
        while(i != -1){
            i = is.read();
            os.write(i);
        }
        is.close();
        os.close();
        long endTime = System.currentTimeMillis();
        System.out.println("程序運(yùn)行時間:"+(endTime-startTime)+"ms");
    }
}
//輸出結(jié)果為:程序運(yùn)行時間40231ms

通過緩沖流提高復(fù)制速度

public class Test {
    public static void main(String[] args) throws IOException{
        long startTime = System.currentTimeMillis();
        BufferedInputStream bis = new BufferedInputStream(new 
                FileInputStream(new File("/Users/zhaokang/Desktop/1.jpg")));
                        BufferedOutputStream bos = new BufferedOutputStream(new 
                FileOutputStream(new File("/Users/zhaokang/Desktop/2.jpg")));
                        int i = 0;
                        while(i != -1){
                            i = bis.read();
                            bos.write(i);
                        }
                        bos.flush();
                        bis.close();
                        bos.close();
        long endTime = System.currentTimeMillis();
        System.out.println("程序運(yùn)行時間:"+(endTime-startTime)+"ms");
    }
}
//輸出結(jié)果為:程序運(yùn)行時間486ms

文件較大時惕耕,做一個緩沖處理

public class Test {
    public static void main(String[] args) throws IOException{
        long startTime = System.currentTimeMillis();
        byte[] tmp = new byte[1024];
        InputStream is = new FileInputStream(new File("/Users/zhaokang/Desktop/1.jpg"));
        OutputStream os = new FileOutputStream(new File("/Users/zhaokang/Desktop/2.jpg"));
        int i = 0;
        while(i != -1){
            i = is.read(tmp);
            os.write(tmp);
        }
        is.close();
        os.close();
        long endTime = System.currentTimeMillis();
        System.out.println("程序運(yùn)行時間:"+(endTime-startTime)+"ms");
    }
}
//輸出結(jié)果為:程序運(yùn)行時間61ms

雙緩沖

public class Test {
    public static void main(String[] args) throws IOException{
        long startTime = System.currentTimeMillis();
        byte[] tmp = new byte[1024];
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("/Users/zhaokang/Desktop/1.jpg")));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("/Users/zhaokang/Desktop/2.jpg")));
        int i = 0;
        while(i != -1){
            i = bis.read(tmp);
            bos.write(tmp);
        }
        bos.flush();
        bis.close();
        bos.close();
        long endTime = System.currentTimeMillis();
        System.out.println("程序運(yùn)行時間:"+(endTime-startTime)+"ms");
    }
}
//輸出結(jié)果為:程序運(yùn)行時間29ms

可以看到第一種情況效率最低,所以若非特殊要求可以放棄這種方法诫肠。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末司澎,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子栋豫,更是在濱河造成了極大的恐慌挤安,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丧鸯,死亡現(xiàn)場離奇詭異蛤铜,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)丛肢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門围肥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蜂怎,你說我怎么就攤上這事穆刻。” “怎么了杠步?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵氢伟,是天一觀的道長。 經(jīng)常有香客問我幽歼,道長朵锣,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任甸私,我火速辦了婚禮诚些,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘颠蕴。我一直安慰自己泣刹,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布犀被。 她就那樣靜靜地躺著,像睡著了一般外冀。 火紅的嫁衣襯著肌膚如雪寡键。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天雪隧,我揣著相機(jī)與錄音西轩,去河邊找鬼员舵。 笑死,一個胖子當(dāng)著我的面吹牛藕畔,可吹牛的內(nèi)容都是我干的马僻。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼注服,長吁一口氣:“原來是場噩夢啊……” “哼韭邓!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起溶弟,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤女淑,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后辜御,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鸭你,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年擒权,在試婚紗的時候發(fā)現(xiàn)自己被綠了袱巨。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡碳抄,死狀恐怖瓣窄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情纳鼎,我是刑警寧澤俺夕,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站贱鄙,受9級特大地震影響劝贸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜逗宁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一映九、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瞎颗,春花似錦件甥、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至倦逐,卻和暖如春譬正,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工曾我, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留粉怕,地道東北人。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓抒巢,卻偏偏與公主長得像贫贝,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蛉谜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容