天天看點

java I/O體系總結java I/O體系總結

java I/O體系總結

I/O流的了解

先看看流的概念

流是一組有順序的,有起點和終點的位元組集合,是對資料傳輸的總稱或抽象。即資料在兩裝置間的傳輸稱為流,流的本質是資料傳輸,根據資料傳輸特性将流抽象為各種類,友善更直覺的進行資料操作。

通俗的說,有兩個檔案A和B,想要把A的内容拷貝到B中,可以假設兩檔案間有一個通道,把A的資料按位元組或是字元的形式傳送給B。這個通道就是java I/O體系流的概念,即可以把流當做抽象的通道。

了解了流的概念,流的分類也就很好明白了。以流的方向來說,流從外界(網絡或磁盤)讀取到程式(記憶體)中,就是輸入流。流從程式流向外界就是輸出流。

java I/O體系總結java I/O體系總結

基礎的流

流又可按傳輸的資料類型分為位元組流和字元流。簡單了解就是傳輸是二進制的位元組(位元組流)還是直接可以看懂的字元(字元流)。結合輸入輸出流,java的I/O流基礎的類(接口)主要有以下幾個:

  1. InputStream(輸入位元組流)
  2. OutputStream(輸出位元組流)
  3. Reader(輸入字元流)
  4. Writer(輸出字元流)

關于位元組流

位元組流是最基本的I/O處理流,之是以基本,是因為所有形式的儲存(檔案,磁盤或網絡)底層都是以位元組形式存儲的。InputStream是所有位元組輸入流的父類,OutputStream是所有位元組輸出流的父類。位元組流主要用于處理二進制資料。處理機關主要是位元組或位元組數組。

關于字元流

鑒于有些檔案是以文本存儲的,為友善操作,于是有了字元流。字元流主要用于處理字元或字元串。每個字元占兩個位元組。在實作上,字元流即由java虛拟機将位元組轉為字元(每2個位元組轉為一個字元)形成的。字元輸入流的父類是Reader,字元輸出流的父類是Writer。

示例

其他流都是基于以上4個基礎接口做的擴充及實作。就以檔案傳輸為例,傳輸類型為位元組,則有FileInputStream(檔案輸入流)和FileOutputStream(檔案輸出流)。看下示例:

/**
     * 輸入流測試
     * 将磁盤中的檔案讀取到記憶體中,以位元組的形式
     * 要讀取的檔案為hello.txt,其中内容為"hello,world"
     */
    @Test
    public void testInputStream() throws Exception {
        InputStream inputStream = null;
        try {
            //代表磁盤檔案
            File file = new File("/Users/wangtonghe/local/tmp/hello.txt");
            // 建構輸入流
            inputStream = new FileInputStream(file);
            int b = 0;
            // 擷取到流的内容
            while ((b = inputStream.read()) != -1) {
                // 輸出流的内容
                System.out.println((b);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }


           

上面這個示例很簡單,就是将待操作檔案包裝到檔案輸入流中,讀取到記憶體。

看一個整體的示例吧,字元類型的檔案輸入輸出。将a.txt的内容拷貝到b.txt中。FileWriter表示檔案字元輸出類,FileReader表示檔案字元輸入類。

一般的做法是,将a.txt包裝到檔案輸入流,讀取到記憶體。再通過檔案輸出流輸出到b.txt檔案中。

用圖表述即為

java I/O體系總結java I/O體系總結
@Test
    public void testFile() throws Exception {

        File aFile = new File("/Users/wangtonghe/local/tmp/a.txt");
        File bFile = new File("/Users/wangtonghe/local/tmp/b.txt");

        FileReader reader = null;
        FileWriter writer = null;

        try {
            // 建構檔案輸入流
            reader = new FileReader(aFile);
            // 建構檔案輸出流
            writer = new FileWriter(bFile);
            char[] chars = new char[1024];
            int len = 0;
            // 讀取輸入流
            if ((len = reader.read(chars)) != -1) {
                //寫入輸出流
                writer.write(chars, 0, len);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                reader.close();
            }
            if (writer != null) {
                writer.close();
            }
        }
    }

           

位元組流與字元流的差別

  1. 操作對象不同,這是最基本的差別。位元組流操作位元組或位元組數組;字元流操作字元或字元串。
  2. 位元組流對終端(檔案等)直接進行操作,而字元流使用緩沖區(即先把資料寫入緩存區,再對緩存區進行操作)
  3. 由于2的存在,對位元組的操作會直接影響終端(檔案)結果,而對字元流的操作最後必須關閉流或強制重新整理流才能寫入資料,否則隻是寫到了緩存區,檔案等終端不受影響。
  4. 詳見 java 位元組流與字元流的差別

兩種流的互相轉化

InputStreamReader以及OutputStreamWriter 負責兩種流的互相轉換。(一般是位元組流轉字元流)

InputStreamReader可以将位元組輸入流轉為字元輸入流;OutputStreamWriter可以将位元組輸出流轉為字元輸出流。

轉化過程如下:

//文本檔案
 File aFile = new File("/Users/wangtonghe/local/tmp/a.txt");
 // 檔案位元組流
 FileInputStream fileInputStream = new FileInputStream(aFile);
 // 位元組流轉為字元流
 Reader reader = new InputStreamReader(fileInputStream);

           

轉化流構造方法及用法如下

  1. InputStreamReader(InputStream); //通過構造函數初始化,使用的是本系統預設的編碼表GBK。
  2. InputStreamReader(InputStream input,String charSet); //通過該構造函數初始化,可以指定編碼表。
  3. OutputStreamWriter(OutputStream); //通過該構造函數初始化,使用的是本系統預設的編碼表GBK。
  4. OutputStreamWriter(OutputStream,String charSet); //通過該構造函數初始化,可以指定編碼表

I/O流概覽

java I/O體系總結java I/O體系總結

java體系I/O流大緻類及結構就如上圖所示。

簡要介紹一下

輸入位元組流InputStream

  1. InputStream 是所有的輸入位元組流的父類,它是一個抽象類。
  2. ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三種基本的媒體流,它們分别從Byte數組、StringBuffer、和本地檔案中讀取資料。
  3. ObjectInputStream 和所有FilterInputStream 的子類都是裝飾流(裝飾器模式的主角)。

同理輸出位元組流OutputStream與此類似

  1. OutputStream 是所有的輸出位元組流的父類,它是一個抽象類。
  2. ByteArrayOutputStream、FileOutputStream 是兩種基本的媒體流,它們分别向Byte 數組、和本地檔案中寫入資料。
  3. ObjectOutputStream 和所有FilterOutputStream 的子類都是裝飾流。

I/O體系的裝飾器模式

關于I/O體系,一定要談的就是其裝飾器的設計模式。

裝飾器模式

概念 裝飾器模式(Decorator Pattern)允許向一個現有的對象添加新的功能,同時又不改變其結構。它能讓我們在擴充類的時候讓系統較好的保持靈活性。

這裡就不具體介紹裝飾器模式了,可以看看Java設計模式12:裝飾器模式

java I/O中實作裝飾器模式主要由FilterInputStream及其子類(輸入流)和FilterOutputStream及其子類完成。

如BufferedInputStream,有緩沖功能的輸入流,可修飾FileIntputStream使其擁有緩沖功能。

BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("/home/user/abc.txt")));

參考文章

  1. java 位元組流與字元流的差別
  2. 位元組流與字元流的差別詳解
  3. Java IO流學習總結一:輸入輸出流
  4. Java設計模式12:裝飾器模式
  5. Java IO : 流,以及裝飾器模式在其上的運用