06-Java IO流
Java IO体系庞大,分为字节流和字符流,输入流和输出流。NIO提供非阻塞IO,适合高性能场景。
IO流体系
字节流(8位)
├── InputStream(输入)
│ ├── FileInputStream
│ ├── ByteArrayInputStream
│ ├── BufferedInputStream
│ └── ObjectInputStream
└── OutputStream(输出)
├── FileOutputStream
├── ByteArrayOutputStream
├── BufferedOutputStream
└── ObjectOutputStream
字符流(16位,Unicode)
├── Reader(输入)
│ ├── FileReader
│ ├── BufferedReader
│ ├── InputStreamReader
│ └── StringReader
└── Writer(输出)
├── FileWriter
├── BufferedWriter
├── OutputStreamWriter
└── PrintWriter
文件操作
字节流读写
import java.io.*;
// 写文件
try (FileOutputStream fos = new FileOutputStream("output.txt")) {
fos.write("Hello".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
// 读文件
try (FileInputStream fis = new FileInputStream("input.txt")) {
int data;
while ((data = fis.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
// 缓冲流(性能更好)
try (BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("output.txt"))) {
bos.write("Buffered write".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
字符流读写
// 写文件
try (FileWriter fw = new FileWriter("output.txt")) {
fw.write("Hello, World!");
} catch (IOException e) {
e.printStackTrace();
}
// 读文件
try (BufferedReader br = new BufferedReader(new FileReader("input.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
// PrintWriter(推荐,功能丰富)
try (PrintWriter pw = new PrintWriter("output.txt")) {
pw.println("Line 1");
pw.printf("Number: %d\n", 42);
} catch (IOException e) {
e.printStackTrace();
}
对象序列化
将对象转为字节流,用于持久化或网络传输。
import java.io.*;
// 可序列化类
public class Student implements Serializable {
private static final long serialVersionUID = 1L; // 版本号
private String name;
private int age;
private transient String password; // transient字段不序列化
// 构造函数、getter/setter...
}
// 序列化
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("student.dat"))) {
Student student = new Student("Alice", 25);
oos.writeObject(student);
} catch (IOException e) {
e.printStackTrace();
}
// 反序列化
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("student.dat"))) {
Student student = (Student) ois.readObject();
System.out.println(student.getName());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
注意:
实现
Serializable接口定义
serialVersionUID(避免版本不兼容)transient字段不序列化静态字段不序列化
Files类(Java 7+)
现代文件操作API,简洁高效。
import java.nio.file.*;
import java.util.List;
// 读取所有行
List<String> lines = Files.readAllLines(Paths.get("file.txt"));
// 读取所有字节
byte[] bytes = Files.readAllBytes(Paths.get("file.txt"));
// 写入
Files.write(Paths.get("output.txt"), "Hello".getBytes());
Files.write(Paths.get("output.txt"), lines); // 写入行列表
// 追加
Files.write(Paths.get("file.txt"), "Append".getBytes(),
StandardOpenOption.APPEND);
// 复制文件
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
// 移动文件
Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);
// 删除文件
Files.delete(path);
Files.deleteIfExists(path);
// 创建目录
Files.createDirectory(path);
Files.createDirectories(path); // 创建多级目录
// 遍历目录
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
for (Path file : stream) {
System.out.println(file.getFileName());
}
}
// 遍历文件树
Files.walk(Paths.get("/path"))
.filter(Files::isRegularFile)
.forEach(System.out::println);
// 文件属性
boolean exists = Files.exists(path);
boolean isDir = Files.isDirectory(path);
long size = Files.size(path);
FileTime modified = Files.getLastModifiedTime(path);
NIO(New IO)
非阻塞IO,适合高并发场景。
Buffer和Channel
import java.nio.*;
import java.nio.channels.*;
// 读文件
try (FileChannel channel = FileChannel.open(
Paths.get("file.txt"), StandardOpenOption.READ)) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (channel.read(buffer) > 0) {
buffer.flip(); // 切换到读模式
while (buffer.hasRemaining()) {
System.out.print((char) buffer.get());
}
buffer.clear(); // 清空,准备下次读
}
} catch (IOException e) {
e.printStackTrace();
}
// 写文件
try (FileChannel channel = FileChannel.open(
Paths.get("output.txt"),
StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {
ByteBuffer buffer = ByteBuffer.wrap("Hello NIO".getBytes());
channel.write(buffer);
} catch (IOException e) {
e.printStackTrace();
}
Selector(IO多路复用)
一个线程管理多个Channel,实现高并发。
import java.nio.channels.*;
// 创建Selector
Selector selector = Selector.open();
// 注册Channel到Selector
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false); // 非阻塞
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
// 事件循环
while (true) {
selector.select(); // 阻塞等待事件
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> it = selectedKeys.iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
if (key.isAcceptable()) {
// 新连接
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel client = server.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
// 数据到达
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = client.read(buffer);
// 处理数据...
}
it.remove(); // 必须移除,否则重复处理
}
}
资源管理
try-with-resources(推荐)
自动关闭实现 AutoCloseable 的资源,避免资源泄漏。
// Java 7+
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"))) {
String line;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
}
} catch (IOException e) {
e.printStackTrace();
}
// 自动调用close(),即使发生异常
传统try-finally
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("file.txt"));
String line = br.readLine();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
对比: try-with-resources更简洁,自动处理异常抑制。
IO vs NIO
特性 |
IO |
NIO |
|---|---|---|
阻塞 |
阻塞 |
非阻塞/阻塞可选 |
流/缓冲 |
面向流 |
面向缓冲区 |
选择器 |
无 |
Selector |
数据处理 |
单向 |
双向 |
线程 |
一线程一连接 |
一线程多连接 |
性能 |
低并发场景够用 |
高并发场景优势明显 |
选择建议:
少量连接:传统IO
大量连接:NIO
文件读写:Files类(最简洁)
高性能服务器:NIO + Selector
简单应用:传统IO + BufferedReader/Writer
最佳实践
优先Files类:Java 7+文件操作首选
使用缓冲流:BufferedReader/Writer性能提升明显
try-with-resources:自动关闭资源
字符流处理文本:Reader/Writer,避免编码问题
字节流处理二进制:InputStream/OutputStream
NIO用于高并发:Selector实现IO多路复用
序列化版本号:serialVersionUID避免不兼容
大文件分块读:避免内存溢出
异步IO(AIO):Java 7+ AsynchronousFileChannel
指定编码:避免平台差异,明确UTF-8
核心: 现代Java优先Files类,传统IO用缓冲流,高并发用NIO。