理解Java中的IO字節流(File的輸入輸出理解)


IO 概述

什么是 IO

Java中IO操作主要是指使用java.io包下的內容,進行輸入、輸出操作。輸入也叫做讀取數據,輸岀也叫做作寫出數據。

IO的分類

根據數據的流向分為:輸入流和輸出流。

輸入流:把數據從其他設備上讀取到內存中的流。

輸出流:把數據從內存中寫出到其他設備上的流。

格局數據的類型分為:字節流和字符流。

頂級父類們

img

字節流

一切文件數據(文本、圖片、視頻等)在存儲時,都是以二進制數字的形式保存,都是一個ー個的字節,在傳輸時也是一樣如此。所以,字節流可以傳輸任意文件數據。在操作流的時候,我們要時刻明確,無論使用什么樣的流對象,底層傳輸的始終為二進制數據。

字節輸出流——OutputStream

java.io.OutputStream抽象類是表示字節輸出流的所有類的超類,將指定的字節信息寫出到目的地。它定義了字節輸出流的基本共性功能方法。

java.io.OutputStream
public abstract void write(int b) throws IOException;
// 將指定的字節輸出流。

public void write(byte b[]) throws IOException{...};
// 將b.length字節從指定的字節數組寫入此輸出流。

public void write(byte b[], int off, int len) throws IOException{...};
// 從指定的字節數組寫入len字節,從偏移量off開始輸出到此輸出流。

public void flush() throws IOException{};
// 刷新此輸出流並強制任何緩沖的輸出字節被寫出。

public void close() throws IOException {};
// 關閉此輸出流並釋放與此流相關聯的任何系統資源。

FileOutputStream類

  1. OutputStream抽象類,有很多的子類,其中FileOutputStream類是它其中一個簡單的子類。
  2. java.io.FileOutputStream是文件輸出流,用於將數據寫出到文件。

寫出字節數據

寫出字節:write(int b)方法,每次可以寫出一個字節數據

字節輸出流的使用步驟:

  1. 創建一個 FileOutputStream對象,構造方法中傳遞寫入數據的目的地。
  2. 調用FileOutputStream對象中的方法write,把數據寫入到文件中。
  3. 釋放資源(流使用會占用一定的內存,使用完畢要把內存清空提供程序的效率)。
import java.io.FileOutputStream;
import java.io.IOException;

public class DemoFosWrite {
    public static void main(String[] args) throws IOException {
        // 使用文件名創建字節流對象
        FileOutputStream fos = new FileOutputStream("FOS.txt");

        // 寫出數據
        // 寫出第一個字節
        fos.write(97);
        // 寫出第二個字節
        fos.write(98);
        // 寫出第三個字節
        fos.write(99);

        // 關閉資源
        fos.close();
    }
}

運行結果:生成了一個"FOS.txt"文件

img

FOS.txt文件大小是3個字節,內容是abc

寫入數據的原理(內存-->硬盤):

Java程序 --> Java虛擬機 --> 操作系統 --> 操作系統調用寫數據的方法 --> 把數據寫到文件中

寫數據的時候,會把要寫入的數據轉換為二進制數。在打開文件的時候,都會查詢編碼表(例如:ASCII表),把字節轉換為字符表示。

write(byte b[])方法

作用:將b.length字節從指定的字節數組寫入此輸出流。

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

public class Demo01Write {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("FOS1.txt");

        byte[] bytes = {97, 98, 99};
        // 將3個字節從bytes字節數組寫入fos輸出流。
        fos.write(bytes);

        fos.close();
    }
}

運行結果:生成了一個"FOS1.txt"文件

img

write(byte b[], int off, int len)方法

作用:從指定的字節數組寫入len字節,從偏移量off開始輸出到此輸出流。

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

public class Demo02Write {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("FOS2.txt");

        byte[] bytes = {97, 98, 99, 100, 101, 102};
        // 將3個字節從bytes字節數組寫入fos輸出流。
        fos.write(bytes, 1, 4);

        fos.close();
    }
}

運行結果:生成了一個"FOS2.txt"文件

img

write方法簡單練習

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;

public class Demo03Write {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("FOS3.txt");

        // 調用String類中的getBytes()方法,把一串字符轉換為byte數組
        byte[] bytes = "大佬,你好!".getBytes();
        // 將該數組轉換為集合輸出
        System.out.println(Arrays.toString(bytes));

        // 將多個字節從bytes字節數組寫入fos輸出流。
        fos.write(bytes);

        fos.close();
    }
}

控制台輸出

[-27, -92, -89, -28, -67, -84, -17, -68, -116, -28, -67, -96, -27, -91, -67, -17, -68, -127]

運行結果:還生成了一個"FOS3.txt"文件

img

字節輸出流的續寫和換行

public FileOutputStream(File file, boolean append)
// 創建文件輸出流以寫入由指定的File對象表示的文件。

public FileOutputStream(String name, boolean append)
// 創建文件輸出流以指定的名稱寫入文件。

這兩個構造方法,參數中都需要傳入一個 boolean類型的值,true表示追加數據,false表示清空原有數據這樣創建的輸出流對象,就可以指定是否追加續寫了,代碼使用演示:

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

public class Demo01OutputAppend {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("a.txt", true);

        // 往"a.txt"文件中寫入"大佬,"內容
        byte[] bytes1 = "大佬,".getBytes();
        fos.write(bytes1);

        // 往"a.txt"文件中追加寫入"你好!"內容
        byte[] bytes2 = "你好!".getBytes();
        fos.write(bytes2);

        fos.close();
    }
}

運行結果:生成了一個"a.txt"文件

img

如果需要換行:

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

public class Demo02OutputAppend {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("b.txt", true);

        // 往"a.txt"文件中寫入"大佬,"內容
        byte[] bytes1 = "大佬,".getBytes();
        fos.write(bytes1);

        // 換行 "\n" 或者 "\r"
        byte[] bytes = "\n".getBytes();
        fos.write(bytes);

        // 往"a.txt"文件中追加寫入"你好!"內容
        byte[] bytes2 = "你好!".getBytes();
        fos.write(bytes2);

        fos.close();
    }
}

運行結果:生成了一個"b.txt"文件

img

字節輸入流 —— InputStream

java.io.InputStream抽象類是表示字節輸入流的所有類的超類,可以讀取字節信息到內存中。它定義了字節輸入流的基本共性功能方法。

public void close()
// 關閉此輸入流並釋放與此流相關聯的任何系統資源。

public abstract int read()
// 從輸入流讀取數據的下一個字節。

public int read(byte[] b)
// 從輸入流中讀取一些字節數,並將它們存儲到字節數組b中。

FileInputStream類

java.io.FileInputStream類是文件輸入流,從文件中讀取字節。

構造方法

public FileInputStream(String name) throws FileNotFoundException
// 通過打開與實際文件的連接來創建一個 FileInputStream,該文件由文件系統中的路徑名name命名。

public FileInputStream(File file) throws FileNotFoundException
// 通過打開與實際文件的連接來創建一個 FileInputStream,該文件由文件系統中的File對象file命名。

當我們創建一個流對象時,必須傳入一個文件路徑。該路徑下,如果沒有該文件,會拋出FileNotFoundException異常。

讀取數據的原理(硬盤-->內存):
Java程序 --> Java虛擬機 --> 操作系統 --> 操作系統調用讀取數據的方法 --> 讀取文件

字節輸入流的使用步驟
  1. 創建FileInputStream對象,構造方法中綁定要讀取的數據源。
  2. 使用FileInputStream對象中的方法read,讀取文件。
  3. 釋放資源。

下面這個例子中使用的read()方法是一個字節一個字節的讀取的。

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

public class DemoInputRead {
    public static void main(String[] args) throws IOException {
        // 創建FileInputStream對象,構造方法中綁定要讀取的數據源
        FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/A");

        // 使用FileInputStream對象中的方法read,讀取文件
        // char=65 對應 A
        int lien0 = fis.read();
        char c0 = (char) lien0;
        System.out.println(lien0 + "對應" + c0);

        // char=10 對應 /n
        int lien1 = fis.read();
        char c1 = (char) lien1;
        System.out.println(lien1 + "對應" + c1);

        // char=66 對應 B
        int lien2 = fis.read();
        char c2 = (char) lien2;
        System.out.println(lien2 + "對應" + c2);

        // char=10 對應 /n
        int lien3 = fis.read();
        char c3 = (char) lien3;
        System.out.println(lien3 + "對應" + c3);

        // 釋放資源
        fis.close();
    }
}

文件A的內容:

img

如果已經將文件A的內容讀取完了,那么再讀取的話,會返回-1。

FileInputStream類中的部分方法

int available()
// 返回此輸入流下一個方法調用可以不受阻塞地從此輸入流讀取(或跳過)的估計字節數。

void close()
// 關閉此輸入流並釋放與該流關聯的所有系統資源。

int read()
// 從輸入流中讀取數據的下一個字節。

int read(byte b[])
// 從輸入流中讀取一定數量的字節,並將其存儲在緩神區數組b中。

int read(byte b[], int off, int len)
// 將輸入流中最多len個數據字節讀入byte數組。

long skip(long n)
// 跳過和丟棄此輸入流中數據的n個字節。
read(byte b[])方法
import java.io.FileInputStream;
import java.io.IOException;

public class Demo02InputRead {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/B");

        // 創建一個byte數組,存儲讀取的字節
        byte[] bytes = new byte[2];

        // 開始讀取,每次讀取兩個
        // 第一次讀取: bytes = {97, 98},len1 = 2
        int len1 = fis.read(bytes);
        System.out.println(
                "bytes = " + new String(bytes)
                + "\t\t"
                + "len = " + len1
        );

        // 開始讀取,每次讀取兩個
        // 第二次讀取: bytes = {99, 100},len2 = 2
        int len2 = fis.read(bytes);
        System.out.println(
                "bytes = " + new String(bytes)
                + "\t\t"
                + "len = " + len2
        );

        // 開始讀取,每次讀取兩個
        // 第三次讀取: bytes = {101, 100},len3 = 2
        int len3 = fis.read(bytes);
        System.out.println(
                "bytes = " + new String(bytes)
                + "\t\t"
                + "len = " + len3
        );

        // 開始讀取,每次讀取兩個
        // 第四次讀取: bytes = {101, 100},len4 = 2
        int len4 = fis.read(bytes);
        System.out.println(
                "bytes = " + new String(bytes)
                + "\t\t"
                + "len = " + len4
        );
    }
}

文件B內容:

img

控制台輸出

bytes = ab        len = 2
bytes = cd        len = 2
bytes = ed        len = 1
bytes = ed        len = -1

解析:

第一次讀取:讀取第1個字節和第2個字節,將初始數組的{0, 0} 替換為 {a, b}

第二次讀取:讀取第3個字節和第4個字節,將第一次讀取后的數組的{a, b} 替換為 {c, d}

第三次讀取:讀取第5個字節,發現沒有可以讀取的了,於是將第二次讀取的數組的 {c, d}里面的c替換為e,而d沒得替換,即{e, d}

第四次讀取:因為第三次讀取的時候,已經讀取完了,沒有可以讀取的了,依舊還是原來的數組{e, d}

第一次讀取兩個字節(len1=2),第二次讀取兩個字節(len2=2),第三次讀取1個字節(len3=2),第四次沒得讀取(len4=-1)。

讀取完后,再讀取,返回值是-1。

字節流練習:圖片復制

文件復制的步驟:

  1. 創建一個字節輸入流對象,構造方法中綁定要讀取的數據源。
  2. 創建一個字節輸出流對象,構造方法中綁定要寫入的目的地。
  3. 使用字節輸入流對象中的方法read讀取文件。
  4. 使用字節輸出流中的方法write,把讀取到的字節寫入到目的地的文件中。
  5. 釋放資源。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class DemoCopyFile {
    public static void main(String[] args) throws IOException {
        // 創建一個字節輸入流對象,構造方法中綁定要讀取的數據源。
        FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo30/666.jpg");

        // 創建一個字節輸出流對象,構造方法中綁定要寫入的目的地。
        FileOutputStream fos = new FileOutputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo30/999.jpg");

        // 使用字節輸入流對象中的方法read讀取文件。
        int len = 0;
        while ((len = fis.read()) != -1) {
            // 使用字節輸出流中的方法write,把讀取到的字節寫入到目的地的文件中。
            fos.write(len);
        }

        // 釋放資源。先關閉寫的,再關閉讀的。
        fis.close();
        fos.close();
    }
}

運行結果:

img

程序優化:

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

public class Demo02CopyFile {
    public static void main(String[] args) throws IOException {
        // 創建一個字節輸入流對象,構造方法中綁定要讀取的數據源。
        FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo30/666.jpg");

        // 創建一個字節輸出流對象,構造方法中綁定要寫入的目的地。
        FileOutputStream fos = new FileOutputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo30/999.jpg");

        // 使用字節輸入流對象中的方法read讀取文件。
        int len = 0;
        byte[] bytes = new byte[1024];
        while ((len = fis.read(bytes)) != -1) {
            // 使用字節輸出流中的方法write,把讀取到的字節寫入到目的地的文件中。
            fos.write(bytes, 0, len);
        }

        // 釋放資源。
        fis.close();
        fos.close();
    }
}


免責聲明!

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



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