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性能?
- 使用缓冲流
- 批量操作
- 选择合适的缓冲区大小
- 使用NIO处理大量连接
- 及时关闭资源
// 优化示例
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);
浙公网安备 33010602011771号