# 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 ``` ## 文件操作 ### 字节流读写 ```java 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(); } ``` ### 字符流读写 ```java // 写文件 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(); } ``` ## 对象序列化 将对象转为字节流,用于持久化或网络传输。 ```java 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,简洁高效。 ```java import java.nio.file.*; import java.util.List; // 读取所有行 List 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 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 ```java 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,实现高并发。 ```java 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 selectedKeys = selector.selectedKeys(); Iterator 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 // 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 ```java 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 ## 最佳实践 1. **优先Files类**:Java 7+文件操作首选 2. **使用缓冲流**:BufferedReader/Writer性能提升明显 3. **try-with-resources**:自动关闭资源 4. **字符流处理文本**:Reader/Writer,避免编码问题 5. **字节流处理二进制**:InputStream/OutputStream 6. **NIO用于高并发**:Selector实现IO多路复用 7. **序列化版本号**:serialVersionUID避免不兼容 8. **大文件分块读**:避免内存溢出 9. **异步IO(AIO)**:Java 7+ AsynchronousFileChannel 10. **指定编码**:避免平台差异,明确UTF-8 **核心:** 现代Java优先Files类,传统IO用缓冲流,高并发用NIO。