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

Java IO 體系深度解析:檔案操作、流分類與裝飾者模式實戰

     編輯:Java 相關知識

Java IO 是資料持久化與網路傳輸的基石。本文系統梳理 java.io 與 java.nio 核心架構,聚焦檔案管理、位元組/字元流體系、緩衝裝飾、隨機存取與壓縮操作,並揭示裝飾者模式在流設計中的精妙應用。

一、檔案與目錄管理:File 類


// 路徑表示(不保證檔案存在)
File f = new File("/data/logs/app.log");
File f2 = new File("/data", "logs/app.log"); // 父目錄 + 子路徑
File f3 = new File(uri); // 從 URI 建立

// 常用查詢
boolean exists = f.exists();
boolean isFile = f.isFile();
boolean isDir = f.isDirectory();
long len = f.length(); // 位元組長度
long lastMod = f.lastModified(); // 毫秒時間戳
String[] names = f.list(); // 列出檔名
File[] files = f.listFiles(); // 列出 File 物件(可傳 FilenameFilter/FileFilter)

// 建立/刪除
f.createNewFile(); // 建立空檔
f.mkdir(); f.mkdirs(); // 建立單層/多層目錄
f.delete(); // 刪除(目錄必須為空)
f.deleteOnExit(); // JVM 退出時刪除

// 路徑轉換
String abs = f.getAbsolutePath();
String canon = f.getCanonicalPath(); // 解析 . .. 符號連結
Path path = f.toPath(); // 互操作 NIO.2

二、流體系總覽:位元組 vs 字元、輸入 vs 輸出、節點 vs 處理

維度位元組流字元流
基類InputStream / OutputStreamReader / Writer
處理單位8-bit byte16-bit char (UTF-16)
典型用途圖片、影音、二進位協議、序列化文字檔、JSON、XML、CSV
轉換橋樑InputStreamReader (解碼) / OutputStreamWriter (編碼)
核心參數:Charset (StandardCharsets.UTF_8)

節點流(直接操作資料源)

  • FileInputStream, FileOutputStream, FileReader, FileWriter
  • ByteArrayInputStream, ByteArrayOutputStream(記憶體緩衝)
  • PipedInputStream, PipedOutputStream(執行緒管道)

處理流(裝飾者模式:包裝節點流或其他處理流)

  • 緩衝:BufferedInputStream, BufferedOutputStream, BufferedReader, BufferedWriter — 大幅提升 I/O 效能,必加。
  • 轉換:InputStreamReader, OutputStreamWriter(指定編碼)。
  • 資料類型:DataInputStream, DataOutputStream(基本型別序列化)。
  • 物件序列化:ObjectInputStream, ObjectOutputStream(需實作 Serializable)。
  • 列印:PrintStream (System.out), PrintWriter(不拋 IOException)。
  • 壓縮:GZIPInputStream, ZipInputStream, JarInputStream。

三、標準流與裝飾鏈實戰


// 讀取 UTF-8 文字檔,逐行處理(標準範本)
try (BufferedReader br = new BufferedReader(
        new InputStreamReader(new FileInputStream("data.txt"), StandardCharsets.UTF_8))) {
    String line;
    while ((line = br.readLine()) != null) {
        process(line);
    }
}

// 寫入 UTF-8 文字檔,緩衝+自動 flush
try (BufferedWriter bw = new BufferedWriter(
        new OutputStreamWriter(new FileOutputStream("out.txt"), StandardCharsets.UTF_8))) {
    bw.write("Hello");
    bw.newLine(); // 跨平台換行
}

// 二進位複製:緩衝位元組流
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("src.bin"));
     BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("dst.bin"))) {
    byte[] buf = new byte[8192];
    int len;
    while ((len = bis.read(buf)) != -1) {
        bos.write(buf, 0, len);
    }
}

四、RandomAccessFile:隨機讀寫與檔案鎖

唯一同時實作 DataInput/DataOutput 且非流繼承體系的類,支援指標跳轉。


// "rw" 讀寫模式
try (RandomAccessFile raf = new RandomAccessFile("data.dat", "rw")) {
    raf.seek(100); // 移動指標
    raf.writeInt(0xCAFEBABE); // 寫入 int
    raf.seek(100);
    int val = raf.readInt(); // 讀回
    
    // 檔案鎖(進程級,跨 JVM 可見)
    FileLock lock = raf.getChannel().tryLock(0, 100, false); // 共享鎖
    if (lock != null) { /* 安全操作 */ lock.release(); }
}

五、壓縮與解壓縮:ZIP/GZIP

建立 ZIP 壓縮包


try (ZipOutputStream zos = new ZipOutputStream(
        new BufferedOutputStream(new FileOutputStream("backup.zip")))) {
    addToZip(zos, new File("src_dir"), "");
}

void addToZip(ZipOutputStream zos, File file, String parent) throws IOException {
    String entryName = parent + file.getName();
    if (file.isDirectory()) {
        zos.putNextEntry(new ZipEntry(entryName + "/"));
        zos.closeEntry();
        for (File child : file.listFiles()) addToZip(zos, child, entryName + "/");
    } else {
        zos.putNextEntry(new ZipEntry(entryName));
        try (FileInputStream fis = new FileInputStream(file)) {
            byte[] buf = new byte[8192];
            int len;
            while ((len = fis.read(buf)) != -1) zos.write(buf, 0, len);
        }
        zos.closeEntry();
    }
}

解壓 ZIP


try (ZipInputStream zis = new ZipInputStream(new FileInputStream("backup.zip"))) {
    ZipEntry entry;
    while ((entry = zis.getNextEntry()) != null) {
        File out = new File("extract_dir", entry.getName());
        if (entry.isDirectory()) { out.mkdirs(); continue; }
        out.getParentFile().mkdirs();
        try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(out))) {
            byte[] buf = new byte[8192];
            int len;
            while ((len = zis.read(buf)) != -1) bos.write(buf, 0, len);
        }
        zis.closeEntry();
    }
}

六、NIO.2 (Java 7+) 現代檔案 API:Path, Files, FileSystem

更豐富、函數式、支援屬性、走訪、監聽:


Path path = Paths.get("/data/logs/app.log");

// 基本操作
Files.createDirectories(path.getParent());
Files.writeString(path, "content", StandardCharsets.UTF_8, StandardOpenOption.CREATE);
String content = Files.readString(path, StandardCharsets.UTF_8);
Files.copy(src, dst, StandardCopyOption.REPLACE_EXISTING);
Files.move(src, dst, StandardCopyOption.ATOMIC_MOVE);
Files.deleteIfExists(path);

// 走訪目錄樹
Files.walkFileTree(Paths.get("/data"), new SimpleFileVisitor() {
    @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
        if (file.toString().endsWith(".log")) process(file);
        return FileVisitResult.CONTINUE;
    }
});

// 監聽目錄變更
WatchService ws = FileSystems.getDefault().newWatchService();
Paths.get("/data").register(ws, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE);
while (true) {
    WatchKey key = ws.take();
    for (WatchEvent ev : key.pollEvents()) { /* 處理事件 */ }
    key.reset();
}

七、效能優化關鍵

  1. 必加緩衝:BufferedInputStream/OutputStream/Reader/Writer,預設 8KB,可調大小。
  2. 批次讀寫:陣列 byte[8192] / char[8192],避免單位元組/字元調用。
  3. 大檔案用 NIO:FileChannel.transferTo/From 零拷貝(Kernel 空間直接傳輸)、MappedByteBuffer 記憶體映射。
  4. 指定編碼:永遠顯式指定 StandardCharsets.UTF_8,避免平台預設編碼差異導致亂碼。
  5. 關閉順序:try-with-resources 自動按相反順序關閉外層流 → 內層流。

結語

掌握「節點流接資料源、處理流裝飾功能」的裝飾者模式本質,熟練組合緩衝、轉碼、壓縮、序列化流,再配合 NIO.2 的 Files/Path 現代 API,即可應對 99% 的 Java IO 場景。記住:無緩衝不 IO,無編碼不字元,無 try-with-resources 不關閉。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved