Java-輸入輸出流的簡單看法與總結

Java-輸入輸出流的簡單看法與總結

 爲什麼Java中關於輸入輸出流(IO流)的對象爲什麼這麼多,實在難以記憶,這可能是絕大多數人在學習關於Java此內容的問題,下面就來總結一下這個知識點,讓這個困難得到解決。

一、理解Java的IO模型和框架

實際上對於Java輸入輸出流的所有概念在下圖中就已經完整地體現了:

在這裏插入圖片描述
還有不得不提一下Java的IO框架:
在這裏插入圖片描述

弄明白上面兩張圖,你就可以說已經理解了Java的IO模型。

 首先,需要理解IO流的各個類是用來做什麼的。比方說:InputStreamReader 類可以用來做什麼,有什麼用途?可能這個問題難道你了,因爲這個類既包括字節流,也囊括了字符流,到底是哪一個流?

有一個規律:

  1. 末尾的單詞決定其是哪一類IO流,所以在此例中,這爲字符流;
  2. 開始的單詞決定的輸入的流類型,或者目的地流類型;
  3. Reader是基於字符的輸入操作流,InputStream是基於字節的輸入操作流
  4. Writer是基於字符的輸出操作流,OutputStream是基於字節的輸出操作流
  5. 輸出/輸出流的分類意味着這個類具有輸出/讀取的功能方法,而不以爲這流本身會主動執行這些方法

 有些既可以是源,也可以是目的地,比如說File,因爲我們既可以從文件中讀取內容,也可以向文件中寫入內容,所以File既可以與InputStream組合,也可以和OutputStream組合;
有些則只能是目的地,或源,比如說InputStream只能和Reader組合,而沒有OutputStreamReader的組合。

 綜上所述,InputStreamReader類使用來讀取字節流數據,得到字符數據來供我對字符流數據進行操作的類,所以這也要求了InputStreamReader類中的大多數方法是基於字符的操作。

注意事項:不要錯認爲IO流操作過程中只有輸出流會對數據進行轉換,比如說字節流轉爲硬盤文件存儲起來,輸入流同樣有轉換數據的功能。

除了用於緩衝作用的流,輸入流可以一下方式理解:

在這裏插入圖片描述
輸出流可以這麼理解:

在這裏插入圖片描述
 對於緩衝IO流的理解:其也是個流對象,不過被稱爲裝飾類流,這主要是通過其對輸入/出流對象裝飾後,我們不再直接調用輸入/出流的讀寫方法,而是調用它緩衝IO流的讀寫方法。但是這個理解還是不夠到位。所有流對象也是位於內存中的,但是緩衝IO流對象還是一個實管理內存的工具,所以可以憑藉此類來和內存直接打交道,優化內存管理,而直接使用輸入輸出流則沒有此功能。

二、活學活用

注意事項:下面的例子沒有進行異常處理以及流的關閉操作,實際上不夠科學,但是這裏不是重點,省略了。

  1. 將一個字符串轉爲文檔儲存起來:

面對這樣一個例子,我們應當怎麼做呢?

我們是否需要一個輸出流對象以及一個輸出流對象呢?

 其實是不需要的,因爲輸入流的作用是讀取數據至內存(或者特殊的內存塊:緩衝IO流),既然String對象以及位於內存中了,不需要輸入流對象,只需要輸出流對象即可。輸出流的前綴很容易判斷:因爲我們生成一個文件,所以此前綴爲File,輸出流的後綴不妨先設置爲OutputStream,我們打算對其進行字節流的操作,所以調用了一下的方法:

byte[] bytes = str.getBytes();,因爲要求輸出流的構造參數需要爲爲字節類型的數據。

注意事項:根據需要確定是否需要輸入流以及輸出流。

/**
 * @author Fisherman
 */
public class MyTry {

    public static void main(String[] args) throws IOException {
        FileWriter fileWriter = new FileWriter("Mystr.txt");

		byte[] bytes = str.getBytes();

        FileOutputStream fileOutputStream = new FileOutputStream("Mystr.txt");

        fileOutputStream.write(bytes);

        fileOutputStream.close();

    }
}

 問題實際上就是確定2個前綴以及兩個後綴,輸出流的前綴很容易判斷:因爲我們生成一個文件,所以此前綴爲File。輸入流的後綴和輸出流的前綴恰好是流的兩端,一定要一致,這裏先選擇OutputStream,

當然我們也可以採用字符流的操作來進行,如下代碼塊:

/**
 * @author Fisherman
 */
public class MyTry {

    public static void main(String[] args) throws IOException {
        String str="hello world i am fisherman!!!!!1233";
        char[] chars =str.toCharArray();
        FileWriter fileWriter = new FileWriter("Mystr.txt");

        fileWriter.write(chars);
        fileWriter.close();

    }
}

注意事項:這裏不要遺漏掉fileWriter的close方法,否則會造成文件寫出失敗。

  1. 將一個文件複製到另一個文件

對於文件的相關操作,推薦使用字節流,並且可以採用緩衝IO流進行包裝:

無緩衝IO流的文件複製代碼塊:

 這裏是兩個文件的輸入和輸出,以及都是使用字節流,所以顯然IO流對象採用的是:FileInputStream以及FileOutputStream。

/**
 * @author Fisherman
 */
public class CopyFIle {
    public static void main(String[] args) throws IOException {
        File inFile = new File("1.txt");
        File outFile = new File("2.txt");

        FileInputStream fins = new FileInputStream(inFile);

        FileOutputStream fouts = new FileOutputStream(outFile);

        int c ;

        while (((c = fins.read()) != -1)) {
            fouts.write(c);
        }

        fins.close();
        fouts.close();

    }
}

 由上面的代碼我們可見其效率是比較低的,因爲我們每次調用方法:fins.read()只能讀取一個字節,然而頻繁地訪問硬盤上的資源是一個效率比較低的做法,所以需要使用緩衝IO流來對其進行裝飾。

使用緩衝IO流進行裝飾的代碼塊:

import java.io.*;

/**
 * @author Fisherman
 */
public class CopyFIle_Buffered {
    public static void main(String[] args) throws IOException {
        File inFile = new File("1.txt");
        File outFile = new File("2.txt");


        FileInputStream fins = new FileInputStream(inFile);

        FileOutputStream fouts = new FileOutputStream(outFile);

        BufferedInputStream bif = new BufferedInputStream(fins);

        BufferedOutputStream bof = new BufferedOutputStream(fouts);

        byte[] bytes = new byte[1024];//每次讀取的最大數據量爲1kb

        int length;

        while ((length = bif.read(bytes,0,1024))!=-1){
            bof.write(bytes,0,length);
        }

        bif.close();
        bof.close();

    }
}

三、總結

 Java的IO流操作實際上理解起來很容易,就簡單確定輸入、輸出流的前綴以及後綴,前綴決定的是輸入、輸出類型,後綴決定read/write方法的參數類型。緩衝IO流我們大可將其視作一塊具有能夠優化數據所佔內存空間大小的“智能”的內存。輸出輸出流的選擇完全可以依靠本文所提到的兩張圖來完成選擇。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章