Java IO 常见考题

1. 字节流 vs 字符流

问题:字节流和字符流的区别?

类型 基类 用途 示例
字节流 InputStream/OutputStream 处理二进制数据 图片、音频、视频
字符流 Reader/Writer 处理文本数据 txt文件、代码文件
// 字节流
FileInputStream fis = new FileInputStream("image.jpg");
FileOutputStream fos = new FileOutputStream("copy.jpg");

// 字符流
FileReader fr = new FileReader("text.txt");
FileWriter fw = new FileWriter("output.txt");

2. 缓冲流的作用

问题:为什么要使用缓冲流?

// 无缓冲 - 每次读写都访问磁盘(慢)
FileReader reader = new FileReader("file.txt");
int ch;
while ((ch = reader.read()) != -1) {
    System.out.print((char)ch); // 每个字符都访问一次磁盘
}

// 有缓冲 - 批量读写(快)
BufferedReader buffered = new BufferedReader(new FileReader("file.txt"));
String line;
while ((line = buffered.readLine()) != null) {
    System.out.println(line); // 一次读取多个字符
}

3. try-with-resources

问题:以下代码有什么问题?如何改进?

// 问题代码
FileReader fr = new FileReader("file.txt");
int data = fr.read();
// 忘记关闭流,造成资源泄漏

// 改进方案
try (FileReader fr = new FileReader("file.txt")) {
    int data = fr.read();
} // 自动关闭

4. read()方法的返回值

问题:以下代码有什么问题?

// 错误代码 - 对文本文件使用字节流
FileInputStream fis = new FileInputStream("file.txt");
byte b = (byte) fis.read(); // 问题:应该用字符流读取文本

// 正确代码 - 使用字符流
FileReader fr = new FileReader("file.txt");
int data = fr.read(); // 返回int,-1表示文件结束
if (data != -1) {
    char c = (char) data; // 转换为字符
}

5. 序列化

问题:对象序列化需要什么条件?

// 必须实现Serializable接口
class Person implements Serializable {
    private static final long serialVersionUID = 1L; // 版本控制
    private String name;
    private transient String password; // 不序列化
    private static String company; // 静态字段不序列化
}

// 序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.dat"));
oos.writeObject(new Person());

// 反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.dat"));
Person p = (Person) ois.readObject();

6. 编码问题

问题:如何避免中文乱码?

// 可能乱码
FileReader reader = new FileReader("chinese.txt");

// 指定编码
FileReader reader = new FileReader("chinese.txt", StandardCharsets.UTF_8);

// 或者使用InputStreamReader
InputStreamReader isr = new InputStreamReader(
    new FileInputStream("chinese.txt"), "UTF-8");

7. NIO vs IO

问题:NIO相比传统IO有什么优势?

特性 传统IO NIO
阻塞性 阻塞 非阻塞
处理方式 面向流 面向缓冲区
选择器 支持Selector
适用场景 连接少,数据量大 连接多,数据量小
// 传统IO
ServerSocket server = new ServerSocket(8080);
Socket client = server.accept(); // 阻塞等待

// NIO
ServerSocketChannel server = ServerSocketChannel.open();
server.configureBlocking(false);
SocketChannel client = server.accept(); // 立即返回

8. 常见陷阱题

问题:以下代码输出什么?

try (FileWriter fw = new FileWriter("test.txt")) {
    fw.write("Hello");
    // 没有调用flush(),数据可能还在缓冲区
}
// try-with-resources会自动调用close(),close()会自动flush()

问题:RandomAccessFile的特点?

RandomAccessFile raf = new RandomAccessFile("file.txt", "rw");
raf.seek(10); // 可以随机定位
raf.writeInt(100); // 可读可写

9. 性能优化

问题:如何提高IO性能?

  1. 使用缓冲流
  2. 批量操作
  3. 选择合适的缓冲区大小
  4. 使用NIO处理大量连接
  5. 及时关闭资源
// 优化示例
try (BufferedInputStream bis = new BufferedInputStream(
    new FileInputStream("large.file"), 8192)) { // 8KB缓冲区
    byte[] buffer = new byte[1024];
    int len;
    while ((len = bis.read(buffer)) != -1) {
        // 批量处理
    }
}

10. 面试高频题

Q1: InputStream的read()方法为什么返回int而不是byte?

答案: 因为byte的范围是-128到127,无法表示文件结束标志-1。int可以表示0-255的字节值和-1的结束标志。

Q2: 什么时候使用字节流,什么时候使用字符流?

答案:

  • 字节流:处理二进制文件(图片、音频、视频、exe文件)
  • 字符流:处理文本文件(txt、java、xml、html文件)

Q3: flush()和close()的区别?

答案:

  • flush():强制刷新缓冲区,将数据写入目标
  • close():关闭流并释放资源,会自动调用flush()

Q4: 如何实现文件的复制?

// 文本文件复制 - 使用字符流
try (FileReader fr = new FileReader("source.txt");
     FileWriter fw = new FileWriter("target.txt")) {
    char[] buffer = new char[1024];
    int len;
    while ((len = fr.read(buffer)) != -1) {
        fw.write(buffer, 0, len);
    }
}

// 二进制文件复制 - 使用字节流
try (FileInputStream fis = new FileInputStream("source.jpg");
     FileOutputStream fos = new FileOutputStream("target.jpg")) {
    byte[] buffer = new byte[1024];
    int len;
    while ((len = fis.read(buffer)) != -1) {
        fos.write(buffer, 0, len);
    }
}

Q5: 什么是装饰器模式在IO中的应用?

答案: BufferedReader包装FileReader,为其添加缓冲功能,这就是装饰器模式的典型应用。

// 基础功能
FileReader fr = new FileReader("file.txt");
// 装饰增强
BufferedReader br = new BufferedReader(fr);