Java IO 流是處理數據輸入輸出的核心機制,分為字節流 (處理二進制數據) 和字符流 (處理文本數據)。本文系統梳理四大抽象基類、核心實現類、裝飾器模式應用、緩衝策略、NIO.2 現代 API 及實戰工具類封裝。
| 類別 | 方向 | 數據類型 | 典型實現 |
|---|---|---|---|
InputStream | 輸入 | 字節 (byte) | FileInputStream, ByteArrayInputStream |
OutputStream | 輸出 | 字節 (byte) | FileOutputStream, ByteArrayOutputStream |
Reader | 輸入 | 字符 (char) | FileReader, StringReader |
Writer | 輸出 | 字符 (char) | FileWriter, StringWriter |
// 字節流 → 字符流 (指定編碼)
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"), "UTF-8");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt"), "UTF-8");
// 緩衝增強
BufferedReader br = new BufferedReader(isr);
BufferedWriter bw = new BufferedWriter(osw);
// 字節流寫入
try (FileOutputStream fos = new FileOutputStream("data.bin")) {
fos.write("Hello".getBytes(StandardCharsets.UTF_8));
fos.flush(); // 強制刷新緩衝區
}
// 字符流寫入 (自動處理編碼)
try (FileWriter fw = new FileWriter("text.txt")) {
fw.write("Hello World");
fw.write('\n');
fw.write(new char[]{'J', 'a', 'v', 'a'});
}
// 字符流讀取
try (FileReader fr = new FileReader("text.txt")) {
char[] buffer = new char[1024];
int len;
while ((len = fr.read(buffer)) != -1) {
System.out.print(new String(buffer, 0, len));
}
}
// 緩衝讀取:按行讀取、減少系統調用
try (BufferedReader br = new BufferedReader(new FileReader("large.txt"))) {
String line;
while ((line = br.readLine()) != null) {
process(line);
}
}
// 緩衝寫入:批量刷新
try (BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt"))) {
for (int i = 0; i < 10000; i++) {
bw.write("Line " + i);
bw.newLine(); // 跨平台換行符
}
// bw.flush(); // 手動刷新,close() 會自動調用
}
// 字節陣列流:內存讀寫
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (DataOutputStream dos = new DataOutputStream(baos)) {
dos.writeInt(123);
dos.writeUTF("Hello");
}
byte[] data = baos.toByteArray();
// 字符串讀寫
StringWriter sw = new StringWriter();
try (PrintWriter pw = new PrintWriter(sw)) {
pw.println("Line 1");
pw.printf("Value: %d%n", 42);
}
String content = sw.toString();
try (DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.dat"))) {
dos.writeBoolean(true);
dos.writeInt(100);
dos.writeDouble(3.14);
dos.writeUTF("中文");
}
try (DataInputStream dis = new DataInputStream(new FileInputStream("data.dat"))) {
boolean b = dis.readBoolean();
int i = dis.readInt();
double d = dis.readDouble();
String s = dis.readUTF(); // 修改版 UTF-8
}
// 要求實現 Serializable
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private transient String password; // 不序列化
// ...
}
// 序列化
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.dat"))) {
oos.writeObject(new User("Alice", "secret"));
}
// 反序列化
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.dat"))) {
User user = (User) ois.readObject();
}
Java IO 經典應用裝飾器模式,動態組合功能:
// 核心:FileInputStream (基本功能)
InputStream is = new FileInputStream("file.txt");
// 層層包裝:緩衝 → 轉換字符 → 按行讀取
Reader reader = new BufferedReader(
new InputStreamReader(
new BufferedInputStream( // 可選:雙層緩衝
new FileInputStream("file.txt")),
StandardCharsets.UTF_8));
FileInputStream (節點流)
↓ 包裝
BufferedInputStream (緩衝)
↓ 包裝
InputStreamReader (字節→字符轉換)
↓ 包裝
BufferedReader (字符緩衝 + readLine)
↓ 使用
readLine() / read(char[])
public final class IoUtils {
private IoUtils() {}
/** 讀取文件為字符串 (UTF-8) */
public static String readString(Path path) throws IOException {
return Files.readString(path, StandardCharsets.UTF_8);
}
/** 讀取文件為字節陣列 */
public static byte[] readBytes(Path path) throws IOException {
return Files.readAllBytes(path);
}
/** 讀取文件所有行 */
public static List<String> readLines(Path path) throws IOException {
return Files.readAllLines(path, StandardCharsets.UTF_8);
}
/** 寫入字符串到文件 */
public static void writeString(Path path, String content) throws IOException {
Files.writeString(path, content, StandardCharsets.UTF_8,
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
}
/** 寫入字節陣列 */
public static void writeBytes(Path path, byte[] data) throws IOException {
Files.write(path, data, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
}
/** 追加寫入 */
public static void appendString(Path path, String content) throws IOException {
Files.writeString(path, content, StandardCharsets.UTF_8,
StandardOpenOption.CREATE, StandardOpenOption.APPEND);
}
/** 大文件複製 (NIO.2 零拷貝) */
public static long copyLarge(Path src, Path dest) throws IOException {
return Files.copy(src, dest, StandardCopyOption.REPLACE_EXISTING);
}
}
public static void copyLargeFile(File src, File dest) throws IOException {
try (FileInputStream fis = new FileInputStream(src);
FileOutputStream fos = new FileOutputStream(dest);
FileChannel inChannel = fis.getChannel();
FileChannel outChannel = fos.getChannel()) {
// NIO Channel 零拷貝 (內核態直接傳輸)
long transferred = 0;
long size = inChannel.size();
while (transferred < size) {
transferred += inChannel.transferTo(transferred, size - transferred, outChannel);
}
}
}
Path path = Paths.get("data", "user.txt"); // 跨平台路徑
// 常用操作
Files.exists(path);
Files.isDirectory(path);
Files.size(path);
Files.deleteIfExists(path);
Files.createDirectories(path.getParent());
Files.list(Paths.get(".")).forEach(System.out::println);
// 遞歸遍歷
Files.walk(Paths.get("src"))
.filter(Files::isRegularFile)
.filter(p -> p.toString().endsWith(".java"))
.forEach(System.out::println);
// 帶深度控制
Files.walkFileTree(Paths.get("."), new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
if (file.toString().endsWith(".log")) {
System.out.println("Log: " + file + " Size: " + attrs.size());
}
return FileVisitResult.CONTINUE;
}
});
WatchService watcher = FileSystems.getDefault().newWatchService();
Paths.get("data").register(watcher, StandardWatchEventKinds.ENTRY_CREATE);
while (true) {
WatchKey key = watcher.take();
for (WatchEvent> event : key.pollEvents()) {
System.out.println("Event: " + event.kind() + " File: " + event.context());
}
key.reset();
}
| 場景 | 推薦做法 | 避免做法 |
|---|---|---|
| 讀寫文本文件 | 顯式指定 StandardCharsets.UTF_8 |
依賴平台默認編碼 |
| 屬性文件 | Java 9+ Properties.load(Reader) 指定編碼 |
Properties.load(InputStream) (ISO-8859-1) |
| 控制台輸出 | IDE/終端設置 UTF-8,JVM -Dfile.encoding=UTF-8 |
假設控制台編碼 |
| 網絡傳輸 | 協定規定編碼 (HTTP Header Content-Type charset) | 雙方編碼不一致 |
// 自動關閉,異常時也會關閉
try (InputStream is = Files.newInputStream(path);
BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
// 使用資源
} // 自動調用 close()
try (FileInputStream fis = new FileInputStream("in.txt");
FileOutputStream fos = new FileOutputStream("out.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos)) {
// 複製邏輯
}
public class DbConnection implements AutoCloseable {
private Connection conn;
// ...
@Override
public void close() throws SQLException {
if (conn != null) conn.close();
}
}
// 使用
try (DbConnection db = new DbConnection()) {
// 數據庫操作
}