15、Java 基础硬核复习:File类与IO流的核心逻辑与面试考点
在Java开发中,File类与IO流是连接程序与外部世界(文件、网络)的核心工具。即使现在有Spring等框架封装了IO操作,底层的流(Stream)概念和序列化机制依然是面试中的必考基础。本章逻辑清晰:先操作"文件本身"(File类),再操作"文件内容"(IO流)。
一、核心知识体系
1. File类:操作文件的"元数据"
java.io.File是文件或目录路径的抽象表示,只能操作文件的元数据 (如创建、删除、重命名、获取大小),不能修改文件内容。
- 路径问题 :
- 绝对路径:从盘符(Windows)或根目录(Linux)开始的完整路径(如
D:/a.txt); - 相对路径:相对于当前项目目录的路径(如
src/a.txt),跨平台需用File.separator(如/或\)。
- 绝对路径:从盘符(Windows)或根目录(Linux)开始的完整路径(如
- 常用方法 :
- 判断:
exists()(是否存在)、isFile()(是否为文件)、isDirectory()(是否为目录); - 创建:
createNewFile()(创建文件)、mkdir()(创建单级目录)、mkdirs()(创建多级目录); - 删除:
delete()(删除文件/空目录,非空目录需先删文件); - 遍历:
listFiles()(返回File对象数组,可结合递归遍历所有子目录和文件)。
- 判断:
2. IO流的分类与体系(重点)
IO流是数据传输的通道,分类依据如下:
- 按数据单位 :
- 字节流(Byte Stream):
InputStream/OutputStream,操作8-bit,适合所有文件(图片、视频、音频); - 字符流(Character Stream):
Reader/Writer,操作16-bit,只适合纯文本文件(如.txt、.java)。
- 字节流(Byte Stream):
- 按流的角色 :
- 节点流:直接作用于数据源(如
FileInputStream读取文件); - 处理流:包在节点流外面,增强功能(如
BufferedInputStream提供缓冲,ObjectInputStream实现序列化)。
- 节点流:直接作用于数据源(如
- 四大核心抽象基类 :
所有流都继承自InputStream(字节输入流)、OutputStream(字节输出流)、Reader(字符输入流)、Writer(字符输出流)。
3. 重要流的实战
(1)文件流:操作文件内容
- 字节流:
FileInputStream(读二进制文件)、FileOutputStream(写二进制文件); - 字符流:
FileReader(读文本文件)、FileWriter(写文本文件)。
(2)缓冲流:提升IO效率的"加速器"
缓冲流内部维护一个缓冲区(默认8KB),减少磁盘IO次数(批量读写),显著提升大文件处理速度。
- 字节缓冲流:
BufferedInputStream(读)、BufferedOutputStream(写); - 字符缓冲流:
BufferedReader(读,提供readLine()方法)、BufferedWriter(写,提供newLine()方法)。
(3)转换流:解决"乱码"的关键
转换流是字节流与字符流的桥梁,核心功能是处理编码与解码(解决乱码问题)。
InputStreamReader:字节输入流 → 字符输入流(需指定编码,如new InputStreamReader(new FileInputStream("a.txt"), "GBK"));OutputStreamWriter:字符输出流 → 字节输出流(同理,指定编码)。
(4)对象流:实现序列化与反序列化
对象流用于将Java对象转换为二进制流(持久化存储或网络传输)。
- 序列化:
ObjectOutputStream(将对象写入文件); - 反序列化:
ObjectInputStream(将文件中的二进制流还原为对象); - 注意:类需实现
Serializable接口(标记接口,无方法),serialVersionUID用于版本控制(反序列化时校验)。
二、高频面试考点(必须掌握)
1. 字节流 vs 字符流(🌟必考Top 1)
- 区别 :
- 字节流按8-bit传输,不处理编码;字符流按16-bit传输,内部根据编码表将字节转换为字符。
- 选择 :
- 纯文本文件(.txt、.java)→ 字符流;
- 二进制文件(图片、视频、音频)→ 字节流(图片不能用字符流,二进制数据无法在编码表中找到对应字符,会导致数据损坏)。
2. read() vs read(byte[]/char[] buffer)(性能差异)
read():每次只读1个字节/字符,频繁操作磁盘,效率极低(类似"用勺子舀水");read(buffer):每次读取一个数组的数据(如1024个),批量读写,效率高(类似"用铲子铲水")。
3. 序列化机制(Serialization)
- 定义:将内存中的Java对象转换为二进制流(持久化存储或网络传输);
Serializable接口:标记接口,告诉JVM该类允许被序列化;serialVersionUID:版本控制,序列化后修改类代码(未改ID)会导致反序列化失败(抛InvalidClassException)。
4. transient关键字(不想序列化的属性)
- 作用:修饰属性(如密码、银行卡号),序列化时忽略该属性,反序列化时该值为默认值(null或0)。
5. 乱码问题(Encoding)
- 原因:编码与解码使用的字符集不一致(如文件用UTF-8存,用GBK读);
- 解决 :使用转换流(
InputStreamReader),并在构造器中显式指定正确编码(如new InputStreamReader(new FileInputStream("a.txt"), "GBK"))。
6. close()与flush()(资源释放)
close():自动调用flush()刷新缓冲区(将缓冲区数据写入文件),并释放系统资源(如文件句柄);- 不关闭的后果:文件被占用无法删除,或缓冲区数据丢失。
- 现代Java开发推荐
try-with-resources自动关闭流(如try (FileInputStream fis = new FileInputStream("a.txt")) {})。
三、学习建议
- 实操对比 :写一个"文件复制"工具,分别用字节流(
FileInputStream+FileOutputStream)和缓冲流(BufferedInputStream+BufferedOutputStream)复制100MB视频,对比耗时(缓冲流效率更高); - 乱码修复 :故意用错误编码读取文本文件(如GBK文件用UTF-8读),观察乱码,再用转换流修复(指定正确编码),这是解决生产环境Bug的基本功。
掌握本章核心知识,不仅能应对面试,更能理解Java与外部交互的本质,为后续学习NIO、网络编程打下基础。