一、Java IO体系概述
Java IO(输入/输出)是Java处理数据输入输出的核心API,它提供了一套完整的机制来处理不同类型的数据源和数据流向。Java IO操作主要基于流(Stream) 的概念,流可以看作是数据流动的通道,数据从源头(如文件、网络、内存等)流向目的地。 根据数据处理方式的不同,Java IO流主要分为两大类:
- 字节流:以字节为单位进行数据读写,可以处理所有类型的数据
- 字符流:以字符为单位进行数据读写,专门处理文本数据
二、IO流核心分类与体系结构
2.1 字节流体系
字节流是Java IO中最基础的流类型,主要用于处理二进制数据。 输入流(InputStream)继承体系:
InputStream(抽象类)
├── FileInputStream(文件输入流)
├── ByteArrayInputStream(字节数组输入流)
├── FilterInputStream(过滤输入流)
│ ├── BufferedInputStream(缓冲输入流)
│ ├── DataInputStream(数据输入流)
│ └── ObjectInputStream(对象输入流)
└── PipedInputStream(管道输入流)
输出流(OutputStream)继承体系:
OutputStream(抽象类)
├── FileOutputStream(文件输出流)
├── ByteArrayOutputStream(字节数组输出流)
├── FilterOutputStream(过滤输出流)
│ ├── BufferedOutputStream(缓冲输出流)
│ ├── DataOutputStream(数据输出流)
│ └── ObjectOutputStream(对象输出流)
└── PipedOutputStream(管道输出流)
2.2 字符流体系
字符流专门用于处理文本数据,支持字符编码转换。
读取流(Reader)继承体系:
Reader(抽象类)
├── InputStreamReader(字节字符转换流)
│ └── FileReader(文件读取流)
├── BufferedReader(缓冲读取流)
├── CharArrayReader(字符数组读取流)
└── StringReader(字符串读取流)
写入流(Writer)继承体系:
Writer(抽象类)
├── OutputStreamWriter(字符字节转换流)
│ └── FileWriter(文件写入流)
├── BufferedWriter(缓冲写入流)
├── CharArrayWriter(字符数组写入流)
├── StringWriter(字符串写入流)
└── PrintWriter(打印写入流)
三、文件操作与File类
File类是Java IO中用于表示文件和目录路径的抽象,它提供了丰富的文件操作方法。
3.1 File类基本操作
csharp
import java.io.File;
import java.io.IOException;
public class FileOperationExample {
public static void main(String[] args) {
// 创建File对象
File file = new File("example.txt");
try {
// 创建新文件
if (file.createNewFile()) {
System.out.println("文件创建成功: " + file.getName());
} else {
System.out.println("文件已存在");
}
// 文件信息获取
System.out.println("文件路径: " + file.getPath());
System.out.println("绝对路径: " + file.getAbsolutePath());
System.out.println("文件大小: " + file.length() + " 字节");
System.out.println("可读: " + file.canRead());
System.out.println("可写: " + file.canWrite());
// 删除文件
if (file.delete()) {
System.out.println("文件删除成功");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.2 目录操作
arduino
import java.io.File;
public class DirectoryExample {
public static void main(String[] args) {
// 创建目录
File dir = new File("myDirectory");
if (!dir.exists()) {
if (dir.mkdir()) {
System.out.println("目录创建成功");
}
}
// 列出目录内容
if (dir.isDirectory()) {
String[] files = dir.list();
System.out.println("目录内容:");
for (String file : files) {
System.out.println(file);
}
}
// 创建多级目录
File multiDir = new File("parent/child/grandchild");
if (multiDir.mkdirs()) {
System.out.println("多级目录创建成功");
}
}
}
四、字节流详细操作
4.1 文件字节流操作
java
import java.io.*;
public class ByteStreamExample {
// 文件写入示例
public static void writeFile(String filename, String content) {
try (FileOutputStream fos = new FileOutputStream(filename)) {
byte[] contentBytes = content.getBytes();
fos.write(contentBytes);
System.out.println("文件写入成功");
} catch (IOException e) {
e.printStackTrace();
}
}
// 文件读取示例 - 单字节读取
public static void readFileSingleByte(String filename) {
try (FileInputStream fis = new FileInputStream(filename)) {
int content;
System.out.println("单字节读取内容:");
while ((content = fis.read()) != -1) {
System.out.print((char) content);
}
System.out.println();
} catch (IOException e) {
e.printStackTrace();
}
}
// 文件读取示例 - 字节数组读取
public static void readFileByteArray(String filename) {
try (FileInputStream fis = new FileInputStream(filename)) {
byte[] buffer = new byte[1024];
int bytesRead;
StringBuilder content = new StringBuilder();
while ((bytesRead = fis.read(buffer)) != -1) {
content.append(new String(buffer, 0, bytesRead));
}
System.out.println("字节数组读取内容: " + content.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String filename = "test.txt";
String content = "Hello, Java IO World!\n这是测试内容。";
writeFile(filename, content);
readFileSingleByte(filename);
readFileByteArray(filename);
}
}
4.2 缓冲字节流操作
缓冲流通过内置缓冲区显著提高IO效率。
java
import java.io.*;
public class BufferedStreamExample {
public static void copyFileWithBuffer(String source, String destination) {
try (FileInputStream fis = new FileInputStream(source);
BufferedInputStream bis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream(destination);
BufferedOutputStream bos = new BufferedOutputStream(fos)) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = bis.read(buffer)) != -1) {
bos.write(buffer, 0, bytesRead);
}
bos.flush(); // 确保所有数据写入
System.out.println("文件复制完成");
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
copyFileWithBuffer("source.txt", "destination.txt");
}
}
五、字符流详细操作
5.1 文件字符流操作
字符流专门用于文本文件处理,支持字符编码。
java
import java.io.*;
public class CharacterStreamExample {
// 使用FileReader和FileWriter
public static void copyTextFile(String source, String destination) {
try (FileReader reader = new FileReader(source);
FileWriter writer = new FileWriter(destination)) {
int character;
while ((character = reader.read()) != -1) {
writer.write(character);
}
System.out.println("文本文件复制完成");
} catch (IOException e) {
e.printStackTrace();
}
}
// 使用指定字符编码
public static void readWithEncoding(String filename, String charset) {
try (InputStreamReader isr = new InputStreamReader(
new FileInputStream(filename), charset)) {
int character;
while ((character = isr.read()) != -1) {
System.out.print((char) character);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
copyTextFile("input.txt", "output.txt");
readWithEncoding("input.txt", "UTF-8");
}
}
5.2 缓冲字符流操作
缓冲字符流提供了行读取等便利方法。
typescript
import java.io.*;
public class BufferedCharacterExample {
public static void readFileLineByLine(String filename) {
try (FileReader fr = new FileReader(filename);
BufferedReader br = new BufferedReader(fr)) {
String line;
int lineNumber = 1;
while ((line = br.readLine()) != null) {
System.out.println("行 " + lineNumber + ": " + line);
lineNumber++;
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void writeToFileWithBuffer(String filename, String[] lines) {
try (FileWriter fw = new FileWriter(filename);
BufferedWriter bw = new BufferedWriter(fw)) {
for (String line : lines) {
bw.write(line);
bw.newLine(); // 写入换行符
}
System.out.println("文件写入完成");
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String[] content = {
"第一行内容",
"第二行内容",
"第三行内容"
};
writeToFileWithBuffer("buffered.txt", content);
readFileLineByLine("buffered.txt");
}
}
六、高级IO操作
6.1 对象序列化
序列化允许将对象转换为字节流进行存储或传输。
java
import java.io.*;
import java.util.Date;
class User implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private transient String password; // transient字段不序列化
private Date createTime;
public User(String name, String password) {
this.name = name;
this.password = password;
this.createTime = new Date();
}
// getter和setter方法
@Override
public String toString() {
return "User{name='" + name + "', createTime=" + createTime + "}";
}
}
public class SerializationExample {
public static void serializeObject(User user, String filename) {
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream(filename))) {
oos.writeObject(user);
System.out.println("对象序列化完成");
} catch (IOException e) {
e.printStackTrace();
}
}
public static User deserializeObject(String filename) {
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream(filename))) {
User user = (User) ois.readObject();
System.out.println("对象反序列化完成");
return user;
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
User user = new User("张三", "123456");
serializeObject(user, "user.ser");
User deserializedUser = deserializeObject("user.ser");
if (deserializedUser != null) {
System.out.println("反序列化结果: " + deserializedUser);
}
}
}
6.2 数据流操作
数据流用于读写基本数据类型。
java
import java.io.*;
public class DataStreamExample {
public static void writePrimitiveData(String filename) {
try (DataOutputStream dos = new DataOutputStream(
new FileOutputStream(filename))) {
dos.writeInt(100);
dos.writeDouble(3.14159);
dos.writeBoolean(true);
dos.writeUTF("Hello, DataStream!");
System.out.println("基本数据类型写入完成");
} catch (IOException e) {
e.printStackTrace();
}
}
public static void readPrimitiveData(String filename) {
try (DataInputStream dis = new DataInputStream(
new FileInputStream(filename))) {
int intValue = dis.readInt();
double doubleValue = dis.readDouble();
boolean booleanValue = dis.readBoolean();
String stringValue = dis.readUTF();
System.out.println("读取结果:");
System.out.println("int: " + intValue);
System.out.println("double: " + doubleValue);
System.out.println("boolean: " + booleanValue);
System.out.println("String: " + stringValue);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
writePrimitiveData("data.bin");
readPrimitiveData("data.bin");
}
}
七、NIO简介与比较
Java NIO(New IO)提供了更高效的IO处理方式:
7.1 传统IO vs NIO
| 特性 | 传统IO | NIO |
|---|---|---|
| 数据处理方式 | 流导向 | 缓冲区导向 |
| 阻塞模式 | 阻塞IO | 非阻塞IO可选 |
| 选择器 | 不支持 | 支持 |
| 性能 | 连接数少时良好 | 连接数多时更优 |
7.2 基本NIO操作示例
typescript
import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.util.List;
public class NIOExample {
public static void nioReadFile(String filename) {
try {
Path path = Paths.get(filename);
List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
System.out.println("NIO读取文件内容:");
for (String line : lines) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void nioWriteFile(String filename, List<String> content) {
try {
Path path = Paths.get(filename);
Files.write(path, content, StandardCharsets.UTF_8);
System.out.println("NIO文件写入完成");
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
List<String> content = List.of("NIO第一行", "NIO第二行", "NIO第三行");
nioWriteFile("nio_example.txt", content);
nioReadFile("nio_example.txt");
}
}
八、实践与性能优化
8.1 拷贝文件
使用try-with-resources确保资源正确关闭。
arduino
import java.io.*;
public class BestPracticeExample {
public static void copyFileBestPractice(String source, String destination) {
// 使用try-with-resources自动关闭资源
try (InputStream in = new FileInputStream(source);
OutputStream out = new FileOutputStream(destination)) {
byte[] buffer = new byte[8192]; // 8KB缓冲区
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
System.err.println("文件操作失败: " + e.getMessage());
// 适当的错误处理和日志记录
}
}
public static void main(String[] args) {
copyFileBestPractice("source.txt", "destination.txt");
}
}
8.2 性能优化建议
- 使用缓冲流:对于频繁的读写操作,始终使用缓冲流
- 选择合适的缓冲区大小:通常8KB是比较理想的缓冲区大小
- 及时关闭资源:使用try-with-resources确保资源释放
- 选择合适的流类型:文本数据用字符流,二进制数据用字节流
- 考虑使用NIO:对于高性能要求的场景考虑使用NIO
9. 总结
Java IO提供了强大而灵活的数据处理能力,主要包括:
- 字节流用于处理所有类型的数据,特别是二进制数据
- 字符流专门用于文本处理,支持字符编码
- 缓冲流提高IO操作效率
- 对象序列化用于对象持久化
- NIO提供更高效的IO处理方案
掌握Java IO体系对于任何Java开发者都是必备技能,合理的IO操作能够显著提升应用程序的性能和稳定性。建议根据具体需求选择合适的IO类,并遵循最佳实践来编写健壮的IO代码。