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

Java IO 流核心技術:文件編碼、File 類、RandomAccessFile 與字節/字符流全解析

     編輯:Java 綜合教學

Java IO 流核心技術:文件編碼、File 類、RandomAccessFile 與字節/字符流全解析

一、文件編碼基礎與實戰

字符在不同編碼下佔用字節數不同:

  • UTF-8:中文 3 字節,英文 1 字節,變長編碼,兼容 ASCII
  • GBK:中文 2 字節,英文 1 字節,中文環境常用
  • UTF-16BE:中英文均 2 字節,定長編碼,Java 內部 char 採用此編碼

核心代碼演示

String s = "好好學習ABC";
byte[] utf8 = s.getBytes("UTF-8");   // 中文3字節,英文1字節
byte[] gbk = s.getBytes("GBK");      // 中文2字節,英文1字節
byte[] utf16be = s.getBytes("UTF-16BE"); // 均2字節

// 正確解碼:必須使用與編碼一致的字符集
String correct = new String(utf16be, "UTF-16BE");
String garbled = new String(utf16be); // 默認編碼解碼 → 亂碼

關鍵技術點

  • b & 0xFF:將 signed byte 轉為 unsigned int 顯示十六進制,避免符號位擴展
  • 文本文件本質是字節序列,讀寫必須指定編碼,否則產生亂碼
  • Windows 記事本默認 ANSI(GBK),現代 IDE 項目建議統一 UTF-8

二、File 類:文件與目錄元數據操作

java.io.File 只代表路徑元數據(名稱、大小、權限、時間),不處理文件內容。

常用 API

遞歸遍歷目錄實戰

public static void listDirectory(File dir) throws IOException {
    if (!dir.exists() || !dir.isDirectory()) {
        throw new IllegalArgumentException("無效目錄: " + dir);
    }
    File[] files = dir.listFiles();
    if (files != null) {
        for (File f : files) {
            if (f.isDirectory()) {
                listDirectory(f); // 遞歸
            } else {
                System.out.println(f.getAbsolutePath());
            }
        }
    }
}

三、RandomAccessFile:隨機讀寫文件

支援「讀+寫」模式("rw"),內部維護文件指針,可隨機定位任意位置,適合斷點續傳、大文件隨機訪問場景。

核心方法

  • getFilePointer() / seek(pos):獲取/設置指針位置
  • read() / write(int):單字節讀寫
  • read(byte[]) / write(byte[]):批量讀寫
  • readInt() / writeInt(int):直接讀寫 int(4 字節,大端序)
  • length():文件長度

實戰:寫入字符串與 int,再完整讀回

RandomAccessFile raf = new RandomAccessFile(file, "rw");
raf.write('A'); raf.write('B');
raf.writeInt(0x7FFFFFFF); // 直接寫入 4 字節
raf.write("中".getBytes("GBK")); // GBK 編碼 2 字節

raf.seek(0); // 重置指針
byte[] buf = new byte[(int) raf.length()];
raf.read(buf); // 一次性讀滿
raf.close();

四、字節流體系:InputStream / OutputStream

核心流類別層次

  • 節點流:FileInputStream、FileOutputStream 直接操作文件
  • 處理流/包裝流:
    • DataInputStream/DataOutputStream:按基本類型讀寫
    • BufferedInputStream/BufferedOutputStream:緩衝區提升性能(8KB 默認)

三種拷貝方式性能對比

// 1. 單字節無緩衝 - 最慢
while ((c = in.read()) != -1) out.write(c);

// 2. 字節數組批量讀寫 - 推薦
byte[] buf = new byte[8 * 1024];
int len;
while ((len = in.read(buf)) != -1) out.write(buf, 0, len);

// 3. 緩衝流單字節 - 有緩衝但單字節調用,次之
BufferedInputStream bis = new BufferedInputStream(in);
BufferedOutputStream bos = new BufferedOutputStream(out);
while ((c = bis.read()) != -1) bos.write(c);

實測 10MB 文件:方式 1 約 20s,方式 2 約 7ms,方式 3 約 10ms。結論:批量讀寫 + 緩衝流是最佳實踐。

五、字符流體系:Reader / Writer

字符流 = 字節流 + 編碼轉換器,處理文本文件首選。

轉換流:橋接字節與字符

InputStreamReader isr = new InputStreamReader(new FileInputStream("utf8.txt"), "UTF-8");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("out.txt"), "UTF-8");

char[] buf = new char[8192];
int len;
while ((len = isr.read(buf)) != -1) {
    osw.write(buf, 0, len);
}

便捷文件字符流

  • FileReader / FileWriter:默認使用平台默認編碼,**生產環境不推薦**(跨平台亂碼風險)
  • BufferedReader / BufferedWriter:按行讀寫,readLine()、newLine()
  • PrintWriter:格式化輸出,println()、printf()

六、對象序列化與反序列化

  • 實現 Serializable 標記介面(無方法)
  • ObjectOutputStream.writeObject(obj) 持久化
  • ObjectInputStream.readObject() 恢復
  • transient 關鍵字排除敏感/非必需字段
  • serialVersionUID 顯式聲明版本號,避免反序列化失敗

注意事項

  1. 父類未實現 Serializable,反序列化時父類構造器會重新執行
  2. 靜態字段、transient 字段不參與序列化
  3. 序列化破壞單例模式,需實現 readResolve() 返回實例
  4. 跨 JVM 版本兼容性需謹慎測試
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
方法說明
exists()文件/目錄是否存在
mkdir() / mkdirs()創建單級/多級目錄
isDirectory() / isFile()判斷類型
delete()刪除文件/空目錄
createNewFile()創建新文件
getAbsolutePath()獲取絕對路徑
getName() / getParent()獲取名稱/父路徑
listFiles()列出子文件/目錄(返回 File[])