I/O 是程序與外部世界交換數據的橋樑。Java 提供了龐大的 I/O 類庫,本文系統梳理流分類體系、File 類核心操作、裝飾器模式在流中的經典應用、NIO.2 (JDK 7+) 現代文件 API,幫你建立從「字節/字符流」到「Path/Files/Channel」的完整技術棧認知。
| 分類維度 | 輸入流 (讀) | 輸出流 (寫) | 核心抽象基類 |
|---|---|---|---|
| 按數據類型 | 字節流 | 字節流 | InputStream / OutputStream |
| 字符流 | 字符流 | Reader / Writer | |
| 按功能角色 | 節點流 (源頭/終點) | 節點流 | FileInputStream, FileReader, Socket.getInputStream() |
| 處理流 (包裝增強) | 處理流 | BufferedInputStream, InputStreamReader, DataInputStream, GZIPInputStream |
// 字節流
InputStream → FileInputStream / ByteArrayInputStream / FilterInputStream → BufferedInputStream / DataInputStream / GZIPInputStream
OutputStream → FileOutputStream / ByteArrayOutputStream / FilterOutputStream → BufferedOutputStream / DataOutputStream / GZIPOutputStream
// 字符流 (本質:字節流 + 編碼轉換)
Reader → InputStreamReader → FileReader / BufferedReader
Writer → OutputStreamWriter → FileWriter / BufferedWriter / PrintWriter
new File(String pathname) // 絕對/相對路徑字符串
new File(String parent, String child) // 父路徑 + 子路徑
new File(File parent, String child) // 父 File 對象 + 子路徑
new File(URI uri) // file:// 協議 URI
| 分類 | 代表方法 | 說明 |
|---|---|---|
| 屬性獲取 | getName(), getParent(), getPath(), getAbsolutePath(), length(), lastModified(), exists(), isFile(), isDirectory(), isHidden() | 不訪問磁盤內容,僅元數據 |
| 目錄操作 | list(), listFiles(), list(FilenameFilter), mkdir(), mkdirs() | mkdirs() 遞歸創建父目錄 |
| 文件操作 | createNewFile(), delete(), renameTo(File dest), setReadOnly(), setWritable(), setExecutable() | 返回 boolean 表示成功/失敗 |
| 路徑轉換 | toURI(), toPath() (JDK 7+ 通往 NIO.2 橋梁) | 互操作關鍵 |
// 核心結構
abstract class FilterInputStream extends InputStream {
protected volatile InputStream in; // 被裝飾對象
public FilterInputStream(InputStream in) { this.in = in; }
// 核心方法默認委託給 in
public int read() throws IOException { return in.read(); }
public int read(byte[] b) throws IOException { return in.read(b); }
// ... 其他方法同理委託
}
// 具體裝飾器:緩衝增強
class BufferedInputStream extends FilterInputStream {
private byte[] buf = new byte[8192];
private int count = 0, pos = 0;
public BufferedInputStream(InputStream in) { super(in); }
@Override public int read() throws IOException {
if (pos >= count) fill(); // 批量讀入緩衝區
return buf[pos++] & 0xFF;
}
// ... 省略
}
// 具體裝飾器:數據類型讀取
class DataInputStream extends FilterInputStream {
public DataInputStream(InputStream in) { super(in); }
public int readInt() throws IOException { ... } // 讀 4 字節組裝 int
public String readUTF() throws IOException { ... }
}
// 使用:層層包裝,功能疊加
InputStream in = new FileInputStream("data.bin");
InputStream buffered = new BufferedInputStream(in); // +緩衝
DataInputStream data = new DataInputStream(buffered); // +結構化讀取
int value = data.readInt();
設計精髓:單一職責、動態組合、透明委託。每個裝飾器只負責一項增強(緩衝、轉碼、壓縮、加密、結構化讀取),運行時靈活組合,無需為每種組合創建子類。
Path:不可變路徑對象,替代 File,支援相對/絕對、解析、規範化Files:靜態工具類,百餘個原子操作方法FileSystem、FileStore:文件系統級視圖
// 讀寫小文件 (自動管理資源)
List lines = Files.readAllLines(path, StandardCharsets.UTF_8);
Files.write(path, lines, StandardCharsets.UTF_8, StandardOpenOption.CREATE);
// 流式處理大文件
try (Stream stream = Files.lines(path)) {
stream.filter(s -> s.contains("ERROR")).forEach(System.out::println);
}
// 複製/移動/刪除 (原子選項)
Files.copy(src, dest, StandardCopyOption.REPLACE_EXISTING);
Files.move(src, dest, StandardCopyOption.ATOMIC_MOVE);
Files.deleteIfExists(path);
// 目錄遍歷 (支援深度、過濾、訪問選項)
Files.walk(root, 3, FileVisitOption.FOLLOW_LINKS)
.filter(Files::isRegularFile)
.forEach(System.out::println);
// 屬性讀取 (Basic/Dos/Posix/FileOwner)
BasicFileAttributes attr = Files.readAttributes(path, BasicFileAttributes.class);
attr.creationTime(); attr.lastModifiedTime(); attr.size(); attr.isDirectory();
// 臨時文件/目錄
Path tmpFile = Files.createTempFile("prefix", ".tmp");
Path tmpDir = Files.createTempDirectory("mytemp");
// 字節流 → 字符流 (指定編碼)
Reader reader = new InputStreamReader(new FileInputStream("utf8.txt"), "UTF-8");
Writer writer = new OutputStreamWriter(new FileOutputStream("gbk.txt"), "GBK");
// 默認編碼陷阱:FileReader/FileWriter 使用系統默認編碼 (Windows GBK, Linux UTF-8)
// 生產環境**強制指定編碼**,避免跨平台亂碼
Files.readAllLines/Files.write (小) / Files.lines (大)Files.readAllBytes/Files.write (小) / FileInputStream/FileOutputStream + Buffered (大)DataInputStream/DataOutputStream 或 JSON/Protobuf 庫FileChannel + MappedByteBuffer / transferTo/transferFromPath/Files 完全替代 FileJava I/O 經歷了「流→裝飾器→NIO Channel→NIO.2 Path」四代演進。現代開發**首選 NIO.2 (Path/Files)**,兼顧易用性、功能豐富度、異常處理統一、流式/批量靈活切換。理解裝飾器模式在經典流中的應用,能讓你輕鬆閱讀/擴展任何基於流的第三方庫。