本文整理自畢向東老師 Java 基礎視頻第 19 天課程內容,聚焦字節流文件操作核心 API與圖片複製完整實戰,代碼規範、異常處理嚴謹,適合初學者敲碼練手。
Q:字符流可以用於圖片複製嗎?
A:不可以! 字符流讀取時會查碼表將字節轉字符,遇到碼表無對應字節會產生「未知字符」(佔 1 字節),導致數據損壞。同理,字節流若錯誤截斷多字節字符也會亂碼。
鐵律:二進制文件(圖片/視頻/音頻/壓縮包)只能用字節流!
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) 三種重載。// 方式 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();
}
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); }
}
}
}
BufferedInputStream/BufferedOutputStream 包裝上述流,對比複製大文件耗時。RandomAccessFile seek 定位。FileChannel.transferTo() 零拷貝複製,體驗極致性能。