首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

畢向東 Java 基礎視頻教程第 19 天:IO 流實戰——文件字節流讀寫與圖片完整複製

     編輯:Java 綜合教學

畢向東 Java 基礎視頻教程第 19 天:IO 流實戰——文件字節流讀寫與圖片完整複製

本文整理自畢向東老師 Java 基礎視頻第 19 天課程內容,聚焦字節流文件操作核心 API與圖片複製完整實戰,代碼規範、異常處理嚴謹,適合初學者敲碼練手。

知識點 1:字節流 vs 字符流——圖片複製為什麼必須用字節流?

Q:字符流可以用於圖片複製嗎?
A:不可以! 字符流讀取時會查碼表將字節轉字符,遇到碼表無對應字節會產生「未知字符」(佔 1 字節),導致數據損壞。同理,字節流若錯誤截斷多字節字符也會亂碼。
鐵律:二進制文件(圖片/視頻/音頻/壓縮包)只能用字節流!

知識點 2:FileOutputStream 寫入數據

public static void writeFile() throws IOException {
    FileOutputStream fos = new FileOutputStream("fos.txt");
    // 寫入字節數組,getBytes() 默認平台編碼,建議指定 "UTF-8"
    fos.write("abc厲害".getBytes("UTF-8"));
    // 字節流寫入無需 flush,直接 close 即可(底層無緩衝)
    fos.close();
}
  • 構造函數 new FileOutputStream(file, true) 第二參數 true 表示追加模式,默認 false 覆蓋。
  • write(byte[]) / write(byte[], off, len) / write(int) 三種重載。

知識點 3:FileInputStream 三種讀取姿勢

// 方式 0:單字節讀取(極慢,教學演示用)
public static void readFile_0() throws IOException {
    FileInputStream fis = new FileInputStream("fos.txt");
    int ch;
    while ((ch = fis.read()) != -1) {
        System.out.print((char) ch);
    }
    fis.close();
}

// 方式 1:字節數組批量讀取(標準姿勢,1024xN 最優)
public static void readFile_1() throws IOException {
    FileInputStream fis = new FileInputStream("fos.txt");
    byte[] buf = new byte[1024]; // 1024 的倍數利於磁盤塊讀取
    int len;
    while ((len = fis.read(buf)) != -1) {
        // 必須用 len 截取有效部分,避免殘留舊數據
        System.out.print(new String(buf, 0, len, "UTF-8"));
    }
    fis.close();
}

// 方式 2:available() 一次性讀完(僅適用小文件,大文件 OOM 風險)
public static void readFile_2() throws IOException {
    FileInputStream fis = new FileInputStream("fos.txt");
    // available() 返回剩餘可讀字節估計值(含換行符)
    byte[] buf = new byte[fis.available()];
    fis.read(buf); // 一次讀滿
    System.out.print(new String(buf, "UTF-8"));
    fis.close();
}

知識點 4:圖片完整複製實戰(標準模板)

public class CopyPic {
    public static void main(String[] args) {
        FileOutputStream fos = null;
        FileInputStream fis = null;
        try {
            fos = new FileOutputStream("2.png"); // 目標文件
            fis = new FileInputStream("1.png");  // 源文件
            byte[] buf = new byte[1024];
            int len;
            while ((len = fis.read(buf)) != -1) {
                fos.write(buf, 0, len); // 關鍵:用 len 精確寫入
            }
        } catch (Exception e) {
            throw new RuntimeException("複製文件失敗", e); // 保留堆棧
        } finally {
            // 分別關閉,單獨 try-catch,防止一個關閉失敗影響另一個
            try { if (fis != null) fis.close(); } catch (IOException e) { throw new RuntimeException("讀取流關閉失敗", e); }
            try { if (fos != null) fos.close(); } catch (IOException e) { throw new RuntimeException("輸出流關閉失敗", e); }
        }
    }
}

核心最佳實踐總結

  1. 二進制文件必用字節流,字符流會損壞數據。
  2. 批量讀寫用 byte[1024/4096/8192],單字節讀寫性能極差。
  3. 讀取返回 len 必須用於 write(buf, 0, len),否則殘留舊數據導致文件損壞/變大。
  4. 資源關閉放 finally,分別 try-catch,保證雙流都能關閉,異常不吞沒(拋出 RuntimeException 保留堆棧)。
  5. available() 僅適合小文件一次性讀取,大文件會申請巨大數組導致 OOM。

延伸練習

  • 使用 BufferedInputStream/BufferedOutputStream 包裝上述流,對比複製大文件耗時。
  • 實現斷點續傳思路:記錄已讀位置,RandomAccessFile seek 定位。
  • 嘗試 NIO FileChannel.transferTo() 零拷貝複製,體驗極致性能。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved