天天看點

Java I/O流總結(二)

/*
@author StormWangxhu
@date 2017/11/1
*/
           
昨天我們總結了字元的輸入流,主要進行讀寫的功能。今天來看一下位元組流InputStream和OutputStream.
           

位元組流基本架構體系圖

整體體系:

Java I/O流總結(二)

InputStream:

Java I/O流總結(二)

基本概念

和字元流一樣,位元組流也有兩個抽象基類作為其他類的父類。一個是InputStream,一個是OutPutStream.其他的類都是這兩個類的拓展類。
           

(1)特點:

位元組流可以操作任何資料。

(2)注意:

位元組流使用的是位元組數組 byte[]

字元流使用得是字元數組 char[]

  • inputStream

    (1)、inputStream是所有位元組輸入流的父類,是一個抽象類。

    (2)ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三種基本的媒體流,它們分别從Byte 數組、StringBuffer、和本地檔案中讀取資料。

    (3)ObjectInputStream 和所有FilterInputStream 的子類都是裝飾流(裝飾器模式的主角)。

  • outputStream

    (1)、OutputStream 是所有的輸出位元組流的父類,它是一個抽象類。

    (2)、B

    yteArrayOutputStream、FileOutputStream 是兩種基本的媒體流,它們分别向Byte 數組、和本地檔案中寫入資料。PipedOutputStream 是向與其它線程共用的管道中寫入資料。

    (3)、ObjectOutputStream 和所有FilterOutputStream 的子類都是裝飾流。

  • 其他

(1)、LineNumberInputStream 主要完成從流中讀取資料時,會得到相應的行号,至于什麼時候分行、在哪裡分行是由改類主動确定的,并不是在原始中有這樣一個行号。在輸出部分沒有對應的部 分,我們完全可以自己建立一個LineNumberOutputStream,在最初寫入時會有一個基準的行号,以後每次遇到換行時會在下一行添加一個行 号,看起來也是可以的。好像更不入流了。

(2)、PushbackInputStream 的功能是檢視最後一個位元組,不滿意就放入緩沖區。主要用在編譯器的文法、詞法分析部分。輸出部分的BufferedOutputStream 幾乎實作相近的功能。

StringBufferInputStream 已經被Deprecated,本身就不應該出現在InputStream 部分,主要因為String 應該屬于字元流的範圍。已經被廢棄了,當然輸出部分也沒有必要需要它了!還允許它存在隻是為了保持版本的向下相容而已。

(3)、SequenceInputStream 可以認為是一個工具類,将兩個或者多個輸入流當成一個輸入流依次讀取。完全可以從IO 包中去除,還完全不影響IO 包的結構,卻讓其更“純潔”――純潔的Decorator 模式。

(4)、PrintStream 也可以認為是一個輔助工具。主要可以向其他輸出流,或者FileInputStream 寫入資料,本身内部實作還是帶緩沖的。本質上是對其它流的綜合運用的一個工具而已。一樣可以踢出IO 包!System.out 和System.out 就是PrintStream 的執行個體!

下面我們通過案例來分别講解一下這些位元組流的使用。
首先講解一下FileInputStream:
           

案例一:利用位元組流讀取或寫入文本内容到控制台或者文本檔案中

package com.StormWang.InputStream;

import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;

/**
* @author StormWangxhu
* @version 建立時間:2017年11月1日 上午11:19:03
*
*/

 class FileInStream{
     //讀檔案,一個一個的讀,讀一個存一個
     public static void readFile_1(){
         //先寫一個檔案
         FileWriter fileWriter = null ;
         FileInputStream fileInputStream = null ;
         try {
             fileWriter = new FileWriter("input.txt");
             fileWriter.write("FileInputStream,success.");
             fileWriter.flush();
             fileInputStream = new FileInputStream("input.txt");
             int ch =  ;
             while ((ch= fileInputStream.read())!=-) {
                System.out.print((char)ch);
            }
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (Exception e2) {
                    // TODO: handle exception
                    e2.printStackTrace();
                }
            }
            if (fileWriter != null) {
                try {
                    fileWriter.close();
                } catch (Exception e2) {
                    // TODO: handle exception
                    e2.printStackTrace();
                }
            }
        }
     }
     /*
     //讀方法二(讀完之後,一起存起來。)
     public static void readFile_2() {
         FileInputStream fileInputStream = null ;
         try {
            fileInputStream = new FileInputStream("E:\\eclipse-workspace\\day1101\\input.txt");
            byte[] buf = new byte[1024];
            int len = 0 ;
            while ((len = fileInputStream.read()) != -1) {
                System.out.println("len是:"+len);
                //System.out.print(new String(buf,0,len));
                System.out.println(buf);
            }
            System.out.println("buf數組内容:"+buf);

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (Exception e2) {
                    // TODO: handle exception
                    System.out.println("close:"+e2.toString());
                }
            }
        }
     }*/

    }
public class FileInputStreamDemo {
    public static void main(String[] args) {
        FileInStream fileInStream = new FileInStream() ;
        fileInStream.readFile_1();

    }

}
           

我們來看一下結果:

Java I/O流總結(二)

再來看一個執行個體:實作對一個圖檔檔案的複制

案例二:

package com.StormWang.InputStream;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
* @author StormWangxhu
* @version 建立時間:2017年11月1日 下午4:53:32
*
*/
public class CopyPicture {
    /*
     * 實作功能:  實作圖檔檔案的複制
     * 思路:
     * 1、位元組輸入流和圖檔檔案相關聯
     * 2、再用位元組輸入流将圖檔檔案資料寫入到緩沖區中,即位元組數組中
     * 3、通過循環讀寫,完成資料的存儲
     * 4、關閉流資源。
     * */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        FileInputStream  fileInputStream = null;
        FileOutputStream fileOutputStream =null ;
        try {
            fileInputStream = new FileInputStream("F:\\2016\\1.jpg");
            //測試代碼
            System.out.println("已過!");
            fileOutputStream = new FileOutputStream("F:\\2.JPG");
            byte[] buff = new byte[];
            int ch =   ;
            //此處的read()方法可能會抛出IOException異常,我們catch一下。
            while ((ch= fileInputStream.read(buff)) !=-) {

                /*
                 *write方法說明:
                 *write(byte[] b, int off, int len) 
                 *      将指定 byte 數組中從偏移量 off 開始的 len 個位元組寫入此檔案輸出流。 
                 * 
                 * */
                fileOutputStream.write(buff, , ch);
            }
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

}
           
問題:在輸入流和圖檔檔案關聯時,系統找不到指定檔案。
           
Java I/O流總結(二)
F盤檔案如下所示,不知道為什麼會找不到檔案呢?
待解決:。。。。。。。
           
Java I/O流總結(二)

自定義緩沖位元組流

package com.StormWang.InputStream;
/**
* @author StormWangxhu
* @version 建立時間:2017年11月1日 下午6:44:40
*
*/

import java.io.IOException;
import java.io.InputStream;

public class MyBuffereedInputStream {
    private InputStream iStream ;
    private byte[] buff = new byte[];
    private int pos = ,count =  ;
    public MyBuffereedInputStream(InputStream iStream) {
        // TODO Auto-generated constructor stub
        this.iStream = iStream ;
    }
    public int myRead() throws IOException{
        //通過iStream讀取硬碟中的資料,存儲到buff
        //如果count=0,說明byte數組是空的,是以開始讀取資料
        if (count == ) {
            count = iStream.read(buff);
            //标記位
            pos = ;
            //通過下标找到數組
            byte bt = buff[pos];
            //byte數組個數遞減
            count--;
            //移動标記位
            pos++;
            return bt&;
        }
        //如果位元組數組中還有資料,則繼續往出取

        else if (count>) {
            byte bt = buff[pos];
            count--;
            pos++;
            return bt &  ;
        }
        return - ;

    }
    //關閉流方法
    public void myClose() {
        try {
            iStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
           

這樣就完成了自定義位元組流的定義。下面我們來應用一下:

package com.StormWang.InputStream;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
* @author StormWangxhu
* @version 建立時間:2017年11月1日 下午7:08:36
*
*/
public class myBufferedInputStreamTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        FileInputStream fInStream = null;
        MyBuffereedInputStream myBuffereedInputStream = null ;
        BufferedOutputStream bufferedOutputStream = null;
        try {
            fInStream = new FileInputStream("E:\\eclipse-workspace\\day1101\\src\\com\\StormWang\\InputStream\\CopyPicture.java");
            myBuffereedInputStream = new MyBuffereedInputStream(fInStream);
            bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("myBuff.txt"));
            int ch = ;
            while ((ch=myBuffereedInputStream.myRead())!= -) {
                bufferedOutputStream.write(ch);
            }
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally {
            if (myBuffereedInputStream!= null) {
                myBuffereedInputStream.myClose();
            }
            if (bufferedOutputStream != null) {
                try {
                    bufferedOutputStream.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if (fInStream != null) {
                try {
                    fInStream.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

}
           

我們來看一下結果:

Java I/O流總結(二)

讀寫成功!

(待回頭再思考。。。。。。)
**注意:**
位元組流的read()方法讀取一個位元組。為什麼傳回的不是byte類型的,而是int 類型的呢?
因為read方法讀到末尾時傳回的是-.而在所操作的資料中的很容易出現連續多個的情況,而連續讀到個,就是-.導緻讀取會提前停止。
是以将讀到的一個位元組給提升為一個int類型的數值,但是隻保留原位元組,并在剩餘二進制位補.
具體操作是:byte&  or  byte&    
對于write方法,可以一次寫入一個位元組,但接收的是一個int類型數值。隻寫入該int類型的數值的最低一個位元組(位)。即對于write()方法實際上進行了強制轉化的動作。
簡單說:read方法對讀到的資料進行提升。write對操作的資料進行轉換。**
           

轉換流

  • 特點:

    1,是位元組流和字元流之間的橋梁。

    2,該流對象中可以對讀取到的位元組資料進行指定編碼表的編碼轉換。

  • 什麼時候使用呢?

    1,當位元組和字元之間有轉換動作時。

    2,流操作的資料需要進行編碼表的指定時。

    具體的對象展現:這兩個流對象是字元流體系中的成員。

    1,InputStreamReader:位元組到字元的橋梁。

    2,OutputStreamWriter:字元到位元組的橋梁。

    這兩個流對象是字元流體系中的成員。那麼它們有轉換作用,而本身又是字元流。是以在構造的時候,需要傳入位元組流對象進來。

    構造函數:

    InputStreamReader(InputStream):通過該構造函數初始化,使用的是本系統預設的編碼表GBK。

    InputStreamReader(InputStream,StringcharSet):通過該構造函數初始化,可以指定編碼表。

    OutputStreamWriter(OutputStream):通過該構造函數初始化,使用的是本系統預設的編碼表GBK。

    OutputStreamWriter(OutputStream,StringcharSet):通過該構造函數初始化,可以指定編碼表。

我們來看看API是怎麼解釋的:
           
Java I/O流總結(二)

我們通過代碼來示範一下:

小技巧:
 
 *   源:鍵盤錄入 
 *   目的:控制台 
 * @author StormWangxhu 
 * 改變需求:想把鍵盤錄入的資料存儲到一個檔案中 
 *   源:鍵盤 
 *   目的:檔案 
 *    
 * 改變需求:想要将一個檔案資料列印到控制台上 
 *   源:檔案 
 *   目的:控制台 
 *    
 *   ######################流操作的基本規律:############## 
 *     最痛苦的就是流對象有很多,不知道該用哪一個?                                     
 *      通過三個明确來完成:                                                             
 *        明确源和目的                                                            
 *           源:輸入流.    InputStream    Reader                                                   
 *          目的:輸出流.   OutputStream    Writer                                                       
 *        明确操作的資料是否是是純文字    
 *           是純文字:用字元流 
 *         不是純文字:用位元組流     
 *        當體系明确後,再明确要使用哪個具體的對象 
 *           通過裝置來進行區分: 
 *              源裝置:記憶體、硬碟、鍵盤 
 *            目的裝置:記憶體、硬碟(檔案)、控制台             
 *   ----------------------個需求之一-----------------------   
 *     将一個文本檔案中的資料存儲到另一個檔案中  ,也就是複制檔案 
 *          源:因為是源,是以使用讀取流:InputStream     Reader 
 *              a.是不是操作文本檔案? 
 *                   是:這就可以選擇Reader 
 *                 不是:可以選擇InputStream 
 *             這樣下來,所屬體系就明确了。 
 *              
 *             b.接下來就要明确要使用體系中的哪個對象? 
 *               明确裝置:硬碟上的一個檔案 
 *               Reader體系中可以操作檔案的對象是FileReader 
 *             c.是否需要提高效率? 
 *                需要:加入Reader體系的緩區:BufferedReader 
 *                
 *       接下來就是:
 *  ) FileReader  fr =new FileReader("a.txt");         
    ) BufferedReader br = new BufferedReader(fr); 
 *       目的:檔案 OutputStream    Writer 
 *             a.目的是否是純文字的? 
 *                是:Writer 
 *              不是:OutputStream  
 *             b.明确裝置:硬碟上的一個檔案 
 *                Writer體系中可以操作一個檔案的對象是FileWriter 
 *                 
 *             c.是否需要提高效率? 
 *                 需要:加入Writer體系的緩沖區:BufferedWriter 
 *              
 *       接下來就是: 
 * ) FileWriter fw = new FileWriter("b.txt"); 
    ) BufferedWriter bw = new BufferedWriter(fw);  
 *                  
 *     練習: 将一個圖檔檔案中的資料存儲到另一個圖檔中 ,即為copy圖檔,要按照以上的格式去寫                                        
 *          源(是圖檔):因為是源, 是以使用讀取流:InputStream    Reader 
 *                a.是不是操作的純文字檔案? 
 *                 不是:這就可以選擇InputStream 
 *                   是:這就可以選擇 Reader    
 *                b.接下來就要明确要使用體系中的哪個對象?    
 *                   明确裝置:硬碟上的一個圖檔 
 *                   InputStream體系中可以操作圖檔的對象時FileInputStream 
 *                c.是否需要提高效率? 
 *                  
 *  需要:加入InputStream體系的緩沖區:BufferedInputStream 
 *         
 *         接下來就是:
 * FileInputStream fis = new FileInputStream("1.jpg");  BufferedInputStream bis = new BufferedInputStream(fis); 
 *                目的:檔案  OutputStream      Writer 
 *                 a.是否是純文字的檔案? 
 *                    不是:OutputStream  
 *                      是:writer 
 *                 b.明确裝置:硬碟上的一個圖檔 
 *                  
 *    OutputStream體系中可以操作一個檔案的對FileOutputStream 
 *                 c.是否需要提高效率? 
 *                
 *  需要:加入OutputStream體系的緩沖區:BufferedOutputStream     
 *                                                 
 FileOutputStream fos = new FileOutputStream("2.jpg"); 
 *                     
 *  BufferedOutputStream bos =  BufferedOutputStream(fos);                                         
 *                              
           
我們來實作一個功能,把一個 檔案的内容 輸出到 控制台 上
           
package com.StormWang.InputStream;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

/**
* @author StormWangxhu
* @version 建立時間:2017年11月1日 下午8:04:29
*
*/
/*
 * 實作将一個檔案中的内容輸出到控制台上
 * */
public class FileStreamDemo_2 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //建立讀取和寫入對象
        BufferedReader bReader =  null ;
        BufferedWriter bWriter = null ;
        try {
            /**
             * FileinputStream fs = new FileInutStream("E:\\eclipse-workspace\\day1101\\myBuff.txt");
             * InputStreamReader isr = new InputStreamReader(fs);
             * BufferedReader br = new BufferedReader(isr);
             * 以上三句合并為一句如下:
             */
            bReader = new BufferedReader(
                    new InputStreamReader(//将位元組流轉換為字元流。
                            new FileInputStream("E:\\eclipse-workspace\\day1101\\myBuff.txt")));
            bWriter = new BufferedWriter(
                    //将字元流轉化為位元組流
                    //并輸出到控制台上
                    new OutputStreamWriter(System.out));
            //循環讀取
            String lines = null ;
            /**
             * readLine()方法的原理:
             *  其實緩沖區中的readLine()方法,用的還是與緩沖區關聯的流對象的read()方法 。
             *  隻不過,每一次讀到一個字元,先不進行具體的操作,先進行臨時存儲。
             *  當讀到回車标記時,将臨時容器中存儲的資料一次性的傳回。
             * 
             * */
            while ((lines =  bReader.readLine())!= null) {
                //讀一行,寫一行,把每一行都寫到輸出流中
                bWriter.write(lines);
                //寫一行後換一行
                //newLine()方法為跨平台換行。。
                bWriter.newLine();
                //寫一行重新整理一行
                bWriter.flush();
            }
        } catch (FileNotFoundException e) {
            System.out.println("找不到檔案了!");
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally {
            if (bReader!= null) {
                try {
                    bReader.close();
                }catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                if (bWriter!= null) {
                    try {
                        bWriter.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        }
    }

}
           

看一下結果:

Java I/O流總結(二)

輸出成功!

好了,就先總結到這兒吧。如有錯誤,還望指正!