数据流方向
数据类型
InputStream
/OutputStream
),适用于二进制文件(图片、视频)。Reader
/Writer
),自动处理字符编码(如UTF-8),适用于文本文件。缓冲机制
BufferedInputStream
)。字节流
// 文件操作示例
try (FileInputStream fis = new FileInputStream("input.txt");
FileOutputStream fos = new FileOutputStream("output.txt")) {
int data;
while ((data = fis.read()) != -1) {
fos.write(data);
}
} catch (IOException e) {
e.printStackTrace();
}
FileInputStream
、FileOutputStream
、ByteArrayInputStream
、DataInputStream
。字符流
// 文本文件读写示例
try (BufferedReader br = new BufferedReader(new FileReader("input.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();
}
FileReader
、FileWriter
、BufferedReader
、PrintWriter
。Java IO通过装饰器模式组合功能(如BufferedInputStream
包装FileInputStream
):
InputStream is = new BufferedInputStream(new FileInputStream("data.bin"));
Channel
)和缓冲区(Buffer
),支持单线程处理多个连接(Selector模式)。Buffer
用于与Channel交互的数据容器,支持ByteBuffer
、CharBuffer
等。
ByteBuffer buffer = ByteBuffer.allocate(1024); // 分配堆内存缓冲区
buffer.put("Hello".getBytes()); // 写入数据
buffer.flip(); // 切换为读模式
while (buffer.hasRemaining()) {
System.out.print((char) buffer.get());
}
Channel
双向数据通道,支持异步读写,如:
// 文件Channel示例
try (FileChannel channel = new FileInputStream("input.txt").getChannel()) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = channel.read(buffer); // 从通道读取到缓冲区
} catch (IOException e) {
e.printStackTrace();
}
Selector
实现单线程管理多个通道的事件(连接就绪、可读、可写):
Selector selector = Selector.open();
channel.configureBlocking(false); // 设置非阻塞模式
channel.register(selector, SelectionKey.OP_READ); // 注册读事件
while (selector.select() > 0) {
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> it = keys.iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
if (key.isReadable()) {
// 处理读事件
}
it.remove();
}
}
AsynchronousFileChannel
:异步文件操作。AsynchronousSocketChannel
:异步网络通信。// 异步文件读取示例
AsynchronousFileChannel channel = AsynchronousFileChannel.open(
Paths.get("data.txt"), StandardOpenOption.READ);
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer, 0, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
System.out.println("Read " + result + " bytes");
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
exc.printStackTrace();
}
});
特性 | BIO(传统IO) | NIO(非阻塞IO) | AIO(异步IO) |
---|---|---|---|
阻塞模式 | 同步阻塞 | 同步非阻塞 | 异步非阻塞 |
核心组件 | 流(Stream) | 通道(Channel)、缓冲区(Buffer)、选择器(Selector) | 异步通道(AsynchronousChannel) |
线程模型 | 一个连接一个线程 | 一个线程处理多个连接 | 线程池处理回调 |
适用场景 | 连接数少且固定的场景 | 连接数多但短操作的场景(如Web服务器) | 连接数多且长操作的场景(如文件传输) |
文件操作
BufferedReader
/BufferedWriter
(字符流)。FileChannel
+ByteBuffer
(NIO零拷贝)。网络编程
InputStream
/OutputStream
。Selector
+SocketChannel
(如Netty框架)。AsynchronousSocketChannel
(如JDK自带的AsynchronousServerSocketChannel
)。序列化与反序列化
ObjectInputStream
/ObjectOutputStream
实现Java对象的序列化。资源管理
try-with-resources
语句自动关闭流,避免内存泄漏。字符编码
new FileReader("file.txt", StandardCharsets.UTF_8)
),避免乱码。性能优化
BufferedInputStream
等)减少IO次数。FileChannel
替代传统流。异常处理
IOException
及其子类,处理连接断开、文件不存在等异常。FileUtils
)。Files
、ByteStreams
)。通过合理选择IO技术(BIO/NIO/AIO)和工具类库,可显著提升Java应用的性能和可维护性。
java.nio.file
包(JDK 7+)核心类:
Path
:表示文件或目录的路径(替代File
类)。Paths
:工厂类,用于创建Path
实例。Files
:工具类,提供文件操作静态方法(读写、复制、删除等)。// 示例:递归复制目录
Path source = Paths.get("src");
Path target = Paths.get("dst");
Files.walk(source)
.forEach(sourcePath -> {
try {
Path targetPath = target.resolve(source.relativize(sourcePath));
Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
e.printStackTrace();
}
});
java.io.File
(传统文件操作)File file = new File("example.txt");
file.exists(); // 判断文件是否存在
file.isDirectory(); // 是否为目录
file.listFiles(); // 获取目录下的文件列表
file.createNewFile(); // 创建新文件
核心接口:
Serializable
:标记接口,实现该接口的类可被序列化。Externalizable
:自定义序列化逻辑(需实现writeExternal()
和readExternal()
方法)。// 序列化示例
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("data.ser"))) {
oos.writeObject(new User("Alice", 25));
} catch (IOException e) {
e.printStackTrace();
}
// 反序列化示例
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("data.ser"))) {
User user = (User) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
JSON序列化:Jackson、Gson
// Jackson示例
ObjectMapper mapper = new ObjectMapper();
User user = new User("Bob", 30);
String json = mapper.writeValueAsString(user); // 对象转JSON
User deserializedUser = mapper.readValue(json, User.class); // JSON转对象
高性能序列化:Kryo、Protostuff(基于Protobuf)。
java.util.zip
包常用类:
ZipInputStream
/ZipOutputStream
:读写ZIP文件。GZIPInputStream
/GZIPOutputStream
:读写GZIP压缩文件。// ZIP压缩示例
try (ZipOutputStream zos = new ZipOutputStream(
new FileOutputStream("archive.zip"))) {
File file = new File("data.txt");
zos.putNextEntry(new ZipEntry(file.getName()));
try (FileInputStream fis = new FileInputStream(file)) {
byte[] buffer = new byte[1024];
int length;
while ((length = fis.read(buffer)) > 0) {
zos.write(buffer, 0, length);
}
}
zos.closeEntry();
} catch (IOException e) {
e.printStackTrace();
}
// TAR文件操作示例
try (TarArchiveOutputStream taos = new TarArchiveOutputStream(
new FileOutputStream("archive.tar"))) {
TarArchiveEntry entry = new TarArchiveEntry(new File("data.txt"));
taos.putArchiveEntry(entry);
try (FileInputStream fis = new FileInputStream("data.txt")) {
IOUtils.copy(fis, taos);
}
taos.closeArchiveEntry();
} catch (IOException e) {
e.printStackTrace();
}
TCP通信:Socket
(客户端)和ServerSocket
(服务器)。
// 服务器端示例
try (ServerSocket serverSocket = new ServerSocket(8080)) {
Socket clientSocket = serverSocket.accept();
try (BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true)) {
String inputLine;
while ((inputLine = in.readLine()) != null) {
out.println("Server received: " + inputLine);
}
}
} catch (IOException e) {
e.printStackTrace();
}
UDP通信:DatagramSocket
和DatagramPacket
。
JDK 11+ HttpClient(替代HttpURLConnection
):
HttpClient client = HttpClient.newBuilder().build();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/data"))
.GET()
.build();
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
System.out.println(response.body());
Apache HttpClient:功能更丰富,支持连接池、代理等。
// 发送线程
PipedOutputStream pos = new PipedOutputStream();
writerThread = new Thread(() -> {
pos.write("Hello, Pipe!".getBytes());
pos.close();
});
// 接收线程
PipedInputStream pis = new PipedInputStream(pos);
readerThread = new Thread(() -> {
int data;
while ((data = pis.read()) != -1) {
System.out.print((char) data);
}
pis.close();
});
ByteArrayInputStream
/ByteArrayOutputStream
:在内存中读写数据。ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write("Hello, Memory!".getBytes());
byte[] bytes = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
int data;
while ((data = bais.read()) != -1) {
System.out.print((char) data);
}
java.nio.charset
包常用类:
Charset
:表示字符集(如UTF-8、GBK)。CharsetEncoder
/CharsetDecoder
:实现字符与字节的转换。// 字符串编码转换示例
String text = "你好,世界";
Charset utf8 = Charset.forName("UTF-8");
Charset gbk = Charset.forName("GBK");
ByteBuffer utf8Bytes = utf8.encode(text);
CharBuffer gbkChars = gbk.decode(utf8Bytes);
String convertedText = gbkChars.toString();
常用工具类:
FileUtils
:文件操作(读取、写入、复制)。IOUtils
:流操作(关闭、复制、转换为字符串)。// 示例:读取文件内容为字符串
String content = FileUtils.readFileToString(new File("data.txt"), StandardCharsets.UTF_8);
// 示例:复制输入流到输出流
IOUtils.copy(inputStream, outputStream);
核心类:
Files
:文件操作(读取、写入、临时文件)。ByteStreams
/CharStreams
:字节流/字符流操作。// 示例:写入字符串到文件
Files.asCharSink(new File("output.txt"), StandardCharsets.UTF_8).write("Hello, Guava!");
// 示例:读取文件所有行
List<String> lines = Files.asCharSource(new File("input.txt"), StandardCharsets.UTF_8).readLines();
AsynchronousFileChannel
支持回调或Future模式:AsynchronousFileChannel channel = AsynchronousFileChannel.open(
Paths.get("data.txt"), StandardOpenOption.READ);
ByteBuffer buffer = ByteBuffer.allocate(1024);
Future<Integer> result = channel.read(buffer, 0);
while (!result.isDone()) {
// 处理其他任务
}
int bytesRead = result.get();
WatchService watcher = FileSystems.getDefault().newWatchService();
Path dir = Paths.get(".");
dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY);
WatchKey key;
while ((key = watcher.take()) != null) {
for (WatchEvent<?> event : key.pollEvents()) {
System.out.println("Event kind:" + event.kind() +
" Path : " + event.context());
}
key.reset();
}
Java IO体系涵盖传统BIO、NIO、AIO及多种工具类库,选择时需根据场景权衡:
java.nio.file.Files
或Apache Commons IO。Socket
,高并发用Netty(基于NIO)。合理结合JDK原生类库与第三方工具,可大幅提升IO操作的效率和代码简洁性。
Serializable
接口(标记接口,无需实现方法)。ObjectOutputStream
序列化对象。ObjectInputStream
反序列化对象。import java.io.*;
// 1. 定义可序列化的类
class User implements Serializable {
private static final long serialVersionUID = 1L; // 序列化版本号
private String name;
private int age;
// transient字段不会被序列化
private transient String password;
public User(String name, int age, String password) {
this.name = name;
this.age = age;
this.password = password;
}
// Getters and setters
public String getName() { return name; }
public int getAge() { return age; }
public String getPassword() { return password; }
}
public class SerializationExample {
public static void main(String[] args) {
User user = new User("Alice", 30, "securePass");
// 2. 序列化对象到文件
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("user.ser"))) {
oos.writeObject(user);
System.out.println("对象已序列化");
} catch (IOException e) {
e.printStackTrace();
}
// 3. 从文件反序列化对象
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("user.ser"))) {
User deserializedUser = (User) ois.readObject();
System.out.println("反序列化结果:");
System.out.println("Name: " + deserializedUser.getName());
System.out.println("Age: " + deserializedUser.getAge());
System.out.println("Password: " + deserializedUser.getPassword()); // null(transient字段未被序列化)
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
serialVersionUID
:版本控制,建议显式声明以避免反序列化时的InvalidClassException
。transient
关键字:标记不需要序列化的字段(如密码、临时数据)。Serializable
。<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.2</version>
</dependency>
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonExample {
public static void main(String[] args) throws Exception {
User user = new User("Bob", 25, "pass123");
ObjectMapper mapper = new ObjectMapper();
// 1. 对象转JSON字符串
String json = mapper.writeValueAsString(user);
System.out.println("JSON: " + json);
// 2. JSON字符串转对象
User deserializedUser = mapper.readValue(json, User.class);
System.out.println("Name: " + deserializedUser.getName());
}
}
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
import com.google.gson.Gson;
public class GsonExample {
public static void main(String[] args) {
User user = new User("Charlie", 35, "secure123");
Gson gson = new Gson();
// 1. 对象转JSON
String json = gson.toJson(user);
System.out.println("JSON: " + json);
// 2. JSON转对象
User deserializedUser = gson.fromJson(json, User.class);
System.out.println("Age: " + deserializedUser.getAge());
}
}
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
<version>5.4.0</version>
</dependency>
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class KryoExample {
public static void main(String[] args) {
User user = new User("David", 40, "kryoPass");
Kryo kryo = new Kryo();
kryo.register(User.class);
// 1. 序列化
try (Output output = new Output(new FileOutputStream("user.kryo"))) {
kryo.writeObject(output, user);
System.out.println("Kryo序列化完成");
} catch (IOException e) {
e.printStackTrace();
}
// 2. 反序列化
try (Input input = new Input(new FileInputStream("user.kryo"))) {
User deserializedUser = kryo.readObject(input, User.class);
System.out.println("Name: " + deserializedUser.getName());
} catch (IOException e) {
e.printStackTrace();
}
}
}
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.23.4</version>
</dependency>
.proto
文件syntax = "proto3";
package example;
message User {
string name = 1;
int32 age = 2;
string password = 3;
}
import com.google.protobuf.InvalidProtocolBufferException;
public class ProtobufExample {
public static void main(String[] args) {
// 1. 创建对象并序列化
UserProto.User user = UserProto.User.newBuilder()
.setName("Eve")
.setAge(28)
.setPassword("protoPass")
.build();
byte[] bytes = user.toByteArray();
// 2. 反序列化
try {
UserProto.User deserializedUser = UserProto.User.parseFrom(bytes);
System.out.println("Age: " + deserializedUser.getAge());
} catch (InvalidProtocolBufferException e) {
e.printStackTrace();
}
}
}
序列化方式 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
Java原生 | 无需额外依赖,支持复杂对象结构 | 性能较差,字节码大,兼容性差 | 简单内部系统,对象结构稳定 |
JSON(Jackson) | 可读性强,跨语言支持,灵活 | 性能一般,字节码较大 | 前后端交互,REST API |
Kryo | 高性能,字节码小 | 不跨语言,需注册类 | 内部系统高性能场景(如缓存) |
Protobuf | 极致性能,跨语言,强兼容性 | 需要编写.proto 文件,学习成本较高 |
分布式系统,微服务间通信 |
serialVersionUID
控制版本。transient
或Jackson的@JsonIgnore
排除不需要序列化的字段。根据场景选择合适的序列化方式,可显著提升系统的性能和可维护性。