Java IO流詳解(三)----字節流InputStream和OutPutStream


我們都知道在計算機中,無論是文本、圖片、音頻還是視頻,所有的文件都是以二進制(字節)形式存在的,IO流中針對字節的輸入輸出提供了一系列的流,統稱為字節流。字節流是程序中最常用的流。在JDK中,提供了兩個抽象類InputStream和OutputStream,它們是字節流的頂級父類,所有的字節輸入流都繼承自InputStream,所有的字節輸出流都繼承自OutputStream。既然二者是抽象類,那么就不能實例化,都是依賴於具體繼承它們的子類去實現。但二者抽象類中也包含它們各自的方法,如果我們先了解清楚抽象類中每一個方法的含義,那么對於后續具體的子類將會有非常大的幫助。

 

1、字節輸入流InputStream

    InputStream是所有字節輸入流的父類,定義了所有字節輸入流都具有的共同特征。其內部提供的方法如下:

image

上圖中的三個read()方法都是用來讀數據的。

  • int read():每次讀取一個字節,返回讀取到的字節。
  • int read(byte[] b):每次讀取 b 數組長度的字節數,然后返回讀取的字節的個數 [注意與read() 方法的區別],讀到末尾時返回-1。
  • int read(byte[] b,int off,int len):每次讀取 b 數組長度的字節數,從數組b 的索引為off 的位置開始,長度為len個字節。

小貼士:close方法,當完成流的操作時,必須調用此方法,釋放系統資源。

 

其中InputStream的實現類FileInputStream是專門用於讀取文件中的數據,通過它將目標設備上的數據讀入到程序。

FileInputStream的構造方法:

  • FileInputStream(File file): 通過打開與實際文件的連接來創建一個 FileInputStream ,該文件由文件系統中的 File對象 file命名。
  • FileInputStream(String name): 通過打開與實際文件的連接來創建一個 FileInputStream ,該文件由文件系統中的路徑名 name命名。

FileInputStream讀入文件舉例(讀取的hello.txt文件內容是 ABCDEFGH):

package com.thr;

import java.io.*;

/**
 * @author Administrator
 * @date 2020-02-21
 * @desc 字節輸入流FileInputStream
 */
public class FileInputStreamTest {

    public static void main(String[] args)  {
        //定義輸入流
        FileInputStream fis =null;
        try {
            //1、創建文件對象
            File file = new File("D:\\IO\\hello.txt");
            //2、創建輸入流對象
            fis = new FileInputStream(file);
            //用定義字節數組,作為裝字節數據的容器
            byte[] buffer =new byte[5];
            int len;//記錄每次讀取的字節個數
            //System.out.println(fis.read(buffer));
            while ((len=fis.read(buffer))!=-1){
                //轉成String型,否則輸出ASCII碼
                String str=new String(buffer,0,len);
                System.out.println(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //釋放資源
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
運行結果:
ABCDE
FGH

 如果我們在讀取的hello.txt文件中添加幾個中文字,再次用同樣的代碼來運行看一下會發生什么情況(hello.txt內容為  ABCDEFGH中國人):

 運行結果的截圖:

image

可以發現運行的結果出現了亂碼,這是因為每次讀取五個字符,而一個utf-8的中文則占了3個字節,而第二次讀取的時候【中】這個字的字節數並沒有讀完,而【國】字全部讀完了,所以【中】和【人】字都出現了亂碼而【國】沒有出現亂碼。這里畫個圖好理解一點。

image

  為了避免可能出現的亂碼,要么把 byte[] 數組容量增大,要么就使用字符輸入輸出流來處理(對於純文本最好使用字符流)。

 

2、字節輸出流OutputStream

    OutputStream是所有字節輸出流的父類,定義了所有字節輸出流都具有的共同特征。其內部提供的方法如下:

image

上圖中的三個write()方法都是用來寫數據的。

  • void write(int b):把一個字節寫入到文件中。
  • void write(byte[] b):把數組b 中的所有字節寫入到文件中。
  • void write(byte[] b,int off,int len):把數組b 中的字節從 off 索引開始的 len 個字節寫入到文件中。

 

其中OutputStream的實現類FileOutputStream是門用於讀出文件中的數據,通過它將數據從程序輸出到目標設備。

FileOutputStream的構造方法:

  • FileOutputStream(File file):創建文件輸出流以寫入由指定的 File對象表示的文件。
  • FileOutputStream(String name): 創建文件輸出流以指定的名稱寫入文件。
  • FileOutputStream(String name,boolean append): 創建文件輸出流以指定的名稱寫入文件,每次輸出文件是否繼續拼接。

FileOutputStream輸出文件舉例:

package com.thr;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * @author Administrator
 * @date 2020-02-21
 * @desc 字節輸出流FileOutputStream
 */
public class FileOutputStreamTest {

    public static void main (String[] args)  {
        //定義字節輸出流
        FileOutputStream fos =null;
        try {

            //1、創建文件對象
            File file = new File("D:\\IO\\hello.txt");
            //2、創建輸出流對象
            fos = new FileOutputStream(file);

            fos.write(97);
            //后面的 \r\n表示回車換行
            fos.write("中國人!\r\n".getBytes());
            //從索引2開始輸出4個字節
            fos.write("ABCDEFGH".getBytes(),2,4);

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //釋放資源
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

運行后結果是: a中國人!CDEF 。而如果我們多次運行測試代碼會發現,每次運行完程序之后文件大小並沒有改變,說明每次運行都創建了一次新的輸出流對象,每次都清空目標文件中的數據。那么要如何才能保留目標文件中數據,還能繼續追加新數據呢?其實很簡單,如下兩個FileOutputStream構造方法:

  • public FileOutputStream(File file, boolean append)
  • public FileOutputStream(String name, boolean append)

這兩個構造方法,第二個參數中都需要傳入一個boolean類型的值,true表示追加數據,false表示不追加也就是清空原有數據。

 

3、字節流拷貝文件

在應用程序中,IO流通常都是成對出現的,即輸入流和輸出流一起使用。而文件的拷貝就需要通過輸入流來讀取文件中的數據,通過輸出流將數據寫入文件。

package com.thr;

import java.io.*;

/**
 * @author Administrator
 * @date 2020-02-21
 * @desc 將文件從D盤拷貝到C盤
 */
public class FileInputOutputStreamTest {
    public static void main(String[] args) {

        //定義輸入流
        FileInputStream fis =null;
        //定義輸出流
        FileOutputStream fos=null;

        //idea的try-catch快捷鍵Ctrl+Alt+T
        try {
            //創建文件對象
            File f1 = new File("D:\\IO\\1.jpg");
            File f2 = new File("C:\\2.jpg");
            //創建輸入輸出流對象
            fis = new FileInputStream(f1);
            fos = new FileOutputStream(f2);
            //定義讀取的大小
            byte [] bytes = new byte[1024];
            int len;
            //讀取並且讀出
            while((len=fis.read(bytes))!=-1){
                fos.write(bytes, 0, len);
            }
            System.out.println("拷貝成功...");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //釋放
            try {
                fis.close();
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM