InputStream和OutputStream及相關知識匯總

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

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

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

基于字節(jié)流的Stream:通常以OutputStream和InputStream結尾,DataOutputStream、DataInputStream、FileOutputStream……
**基于字符流的Stream:通常以Writer和Reader結尾,PrintWriter、FileWriter、FileReader、StringWriter……

可以發(fā)現(xiàn)絕大部份流都是成對出現(xiàn)的,包括輸入流和輸出流??梢赃@樣理解輸入輸出流
輸入流(InputStream和Reader)可以看作一個出水的水龍頭,具有流出水流的功能,即向程序產(chǎn)生數(shù)據(jù)的功能,read便相當于打開開關,之后便會流出水流(數(shù)據(jù))。
輸出流(OutputStream和Writer)可以看作一個進水的水龍頭,具有儲存水流的功能,即接收程序產(chǎn)生的數(shù)據(jù),write后也相當于打開開關,水流(數(shù)據(jù))流進進水水龍頭。
介紹完了基本概念,現(xiàn)在來看一下基本用法。

InputStream
從流中讀取數(shù)據(jù)
public abstract int read() throws IOException 從輸入流中讀取下一字節(jié)。返回0到255范圍內的int字節(jié)值。如果因為已經(jīng)到達流末尾而沒有可用的字節(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é)數(shù)可能小于該數(shù),也可能為 0。導致這種情況的原因很多,跳過 n 個字節(jié)之前已到達文件末尾只是其中一種可能。返回跳過的實際字節(jié)數(shù)。如果 n 為負,則不跳過任何字節(jié)。此類的 skip 方法創(chuàng)建一個 byte 數(shù)組,然后重復將字節(jié)讀入其中,直到讀夠 n 個字節(jié)或已到達流末尾為止。建議子類提供此方法更為有效的實現(xiàn)。例如,可依賴搜索能力的實現(xiàn)。
public int available() throws IOException 返回此輸入流下一個方法調用可以不受阻塞地從此輸入流讀?。ɑ蛱^)的估計字節(jié)數(shù)(流中尚未被讀取的字節(jié)數(shù))。下一個調用可能是同一個線程,也可能是另一個線程。一次讀取或跳過此估計數(shù)個字節(jié)不會受阻塞,但讀取或跳過的字節(jié)數(shù)可能小于該數(shù)。注意,有些 InputStream 的實現(xiàn)將返回流中的字節(jié)總數(shù),但也有很多實現(xiàn)不會這樣做。試圖使用此方法的返回值分配緩沖區(qū),以保存此流所有數(shù)據(jù)的做法是不正確的。如果已經(jīng)調用 close() 方法關閉了此輸入流,那么此方法的子類實現(xiàn)可以選擇拋出 IOException。類 InputStream 的 available 方法總是返回 0。此方法應該由子類重寫。
關閉流
public void close() throws IOException 關閉輸入流并釋放與該流關聯(lián)的所有系統(tǒng)資源
使用輸入流中的標記
public void mark(int readlimit) 在此輸入流中標記當前位置。對 reset 方法的后續(xù)調用會在最后標記的位置重新定位此流,以便后續(xù)讀取重新讀取相同的字節(jié)。readlimit 參數(shù)表示讀取readmit個字節(jié)數(shù)后標記失效。
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 刷新此輸出流并強制寫出所有緩沖的字節(jié)。如果此流的預期目標是由基礎操作系統(tǒng)提供的一個抽象(如一個文件),則刷新此流只能保證將以前寫入到流的字節(jié)傳遞給操作系統(tǒng)進行寫入,但不保證能將這些字節(jié)實際寫入到物理設備(如磁盤驅動器)。
關閉流
public void close() throws IOException 關閉此輸出流并釋放與此流有關的所有系統(tǒng)資源

通過輸入輸出流復制圖片的例子:

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("程序運行時間:"+(endTime-startTime)+"ms");
    }
}
//輸出結果為:程序運行時間40231ms

通過緩沖流提高復制速度

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("程序運行時間:"+(endTime-startTime)+"ms");
    }
}
//輸出結果為:程序運行時間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("程序運行時間:"+(endTime-startTime)+"ms");
    }
}
//輸出結果為:程序運行時間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("程序運行時間:"+(endTime-startTime)+"ms");
    }
}
//輸出結果為:程序運行時間29ms

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容