一、IO流系统概述
Java的IO系统像是一个管道系统,负责数据的输入和输出。可以分为:
- 字节流:处理二进制数据
- 字符流:处理文本数据
字节流与字符流对比
// 字节流示例:复制图片
public void copyImage(String source, String target) {try (FileInputStream fis = new FileInputStream(source);FileOutputStream fos = new FileOutputStream(target)) {byte[] buffer = new byte[1024];int length;while ((length = fis.read(buffer)) > 0) {fos.write(buffer, 0, length);}}
}// 字符流示例:读取文本
public void readText(String fileName) {try (FileReader reader = new FileReader(fileName);BufferedReader br = new BufferedReader(reader)) {String line;while ((line = br.readLine()) != null) {System.out.println(line);}}
}
常用流的层次结构
InputStream/OutputStream (字节流)
├── FileInputStream/FileOutputStream
├── BufferedInputStream/BufferedOutputStream
└── DataInputStream/DataOutputStreamReader/Writer (字符流)
├── FileReader/FileWriter
├── BufferedReader/BufferedWriter
└── InputStreamReader/OutputStreamWriter
二、NIO(New IO)系统
NIO提供了非阻塞IO操作的能力,特别适合高并发场景。
Buffer和Channel
public class NIOExample {public void readFile(String fileName) throws IOException {// 创建文件通道try (FileChannel channel = FileChannel.open(Paths.get(fileName), StandardOpenOption.READ)) {// 创建缓冲区ByteBuffer buffer = ByteBuffer.allocate(1024);// 读取数据到缓冲区while (channel.read(buffer) != -1) {buffer.flip(); // 切换到读模式while (buffer.hasRemaining()) {System.out.print((char) buffer.get());}buffer.clear(); // 清空缓冲区}}}
}
非阻塞IO示例
public class NonBlockingServer {public void startServer() throws IOException {// 创建选择器Selector selector = Selector.open();// 配置服务器通道ServerSocketChannel serverChannel = ServerSocketChannel.open();serverChannel.bind(new InetSocketAddress(8080));serverChannel.configureBlocking(false);// 注册接受连接事件serverChannel.register(selector, SelectionKey.OP_ACCEPT);while (true) {selector.select();Set<SelectionKey> selectedKeys = selector.selectedKeys();Iterator<SelectionKey> iter = selectedKeys.iterator();while (iter.hasNext()) {SelectionKey key = iter.next();if (key.isAcceptable()) {handleAccept(serverChannel, selector);}iter.remove();}}}
}
三、文件操作最佳实践
文件读写操作
public class FileOperations {// 使用try-with-resources确保资源释放public List<String> readLines(String fileName) {List<String> lines = new ArrayList<>();try (BufferedReader reader = Files.newBufferedReader(Paths.get(fileName), StandardCharsets.UTF_8)) {String line;while ((line = reader.readLine()) != null) {lines.add(line);}}return lines;}// 使用BufferedWriter提高写入性能public void writeLines(String fileName, List<String> lines) {try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(fileName), StandardCharsets.UTF_8)) {for (String line : lines) {writer.write(line);writer.newLine();}}}
}
文件复制与移动
public class FileUtils {// 复制文件public void copyFile(Path source, Path target) throws IOException {// REPLACE_EXISTING:如果目标文件存在则替换// COPY_ATTRIBUTES:复制文件属性Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING,StandardCopyOption.COPY_ATTRIBUTES);}// 移动文件public void moveFile(Path source, Path target) throws IOException {Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);}
}
四、序列化机制
基本序列化
public class SerializationDemo {// 可序列化的类public static class Person implements Serializable {private static final long serialVersionUID = 1L;private String name;private int age;private transient String password; // 不会被序列化}// 序列化对象public void serialize(Person person, String fileName) {try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fileName))) {out.writeObject(person);}}// 反序列化对象public Person deserialize(String fileName) {try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName))) {return (Person) in.readObject();}}
}
五、Path与Files工具类使用
Path类操作
public class PathDemo {public void pathOperations() {Path path = Paths.get("/home/user/docs/file.txt");// 获取文件信息System.out.println("文件名: " + path.getFileName());System.out.println("父目录: " + path.getParent());System.out.println("根目录: " + path.getRoot());// 路径操作Path normalizedPath = path.normalize();Path resolvedPath = path.resolve("another.txt");}
}
Files工具类
public class FilesDemo {public void fileOperations() throws IOException {Path path = Paths.get("example.txt");// 创建文件Files.createFile(path);// 写入内容Files.write(path, "Hello, World!".getBytes());// 读取内容byte[] content = Files.readAllBytes(path);// 检查文件属性System.out.println("是否存在: " + Files.exists(path));System.out.println("是否可读: " + Files.isReadable(path));// 遍历目录try (Stream<Path> paths = Files.walk(Paths.get("."))) {paths.forEach(System.out::println);}}
}
最佳实践建议 💡
- IO操作
- 使用缓冲流提高性能
- 正确关闭资源
- 使用字符流处理文本
- 文件处理
- 使用Files工具类
- 处理文件路径用Path
- 考虑文件编码
- 序列化
- 定义serialVersionUID
- 敏感数据用transient
- 考虑安全性
常见陷阱提醒 ⚠️
- 资源泄露
// 错误:未正确关闭资源
FileInputStream fis = new FileInputStream("file.txt");
// 使用文件...
fis.close(); // 可能永远不会执行// 正确:使用try-with-resources
try (FileInputStream fis = new FileInputStream("file.txt")) {// 使用文件...
}
- 编码问题
// 错误:未指定字符编码
FileReader reader = new FileReader("file.txt");// 正确:指定字符编码
Reader reader = new InputStreamReader(new FileInputStream("file.txt"), StandardCharsets.UTF_8);
- 性能问题
// 低效:逐字节读取
int b;
while ((b = inputStream.read()) != -1) {// 处理字节...
}// 高效:使用缓冲区
byte[] buffer = new byte[8192];
int length;
while ((length = inputStream.read(buffer)) != -1) {// 处理缓冲区...
}
IO和文件处理是Java应用程序的基础功能。掌握这些知识对于开发高质量的应用程序至关重要。记住要注意资源管理、性能优化和错误处理。