Java IO流详解
·
一、File类
1. File类概述
是什么?
-
java.io.File类是文件和目录路径名的抽象表示 -
用于创建、删除、重命名、查询文件和目录
-
注意:File类不能访问文件内容本身,需要IO流
路径表示:
-
相对路径:相对于当前项目的路径
-
绝对路径:从盘符开始的完整路径
-
路径分隔符:
-
Windows:
\` 或/` -
Linux/Unix:
/ -
通用:
File.separator
-
2. 构造方法
// 1. 通过路径字符串创建
File file1 = new File("D:/test/test.txt");
File file2 = new File("test.txt"); // 相对路径
// 2. 通过父路径和子路径字符串创建
File file3 = new File("D:/test", "test.txt");
// 3. 通过父File对象和子路径字符串创建
File parentDir = new File("D:/test");
File file4 = new File(parentDir, "test.txt");
3. 常用方法
创建功能
// 创建目录
boolean mkdir(); // 创建单级目录,父目录必须存在
boolean mkdirs(); // 创建多级目录,父目录不存在会自动创建
// 创建文件
boolean createNewFile(); // 创建新文件,文件不存在才创建
// 示例
File dir = new File("D:/a/b/c");
if (!dir.exists()) {
boolean result = dir.mkdirs(); // 创建多级目录
System.out.println("目录创建结果:" + result);
}
File file = new File("D:/a/b/c/test.txt");
if (!file.exists()) {
boolean result = file.createNewFile(); // 创建文件
System.out.println("文件创建结果:" + result);
}
判断功能
boolean exists(); // 文件或目录是否存在
boolean isDirectory(); // 是否是目录
boolean isFile(); // 是否是文件
boolean isHidden(); // 是否是隐藏文件
boolean canRead(); // 是否可读
boolean canWrite(); // 是否可写
boolean canExecute(); // 是否可执行
boolean isAbsolute(); // 是否是绝对路径
获取功能
String getAbsolutePath(); // 获取绝对路径
String getPath(); // 获取相对路径
String getName(); // 获取文件或目录名
String getParent(); // 获取父目录路径
File getParentFile(); // 获取父目录File对象
long length(); // 获取文件大小(字节),目录返回0
long lastModified(); // 获取最后修改时间(毫秒值)
// 目录相关
String[] list(); // 获取目录下所有文件和目录名
File[] listFiles(); // 获取目录下所有文件和目录的File对象
File[] listFiles(FileFilter filter); // 使用过滤器获取
File[] listFiles(FilenameFilter filter);
// 示例:遍历目录
File dir = new File("D:/test");
if (dir.exists() && dir.isDirectory()) {
File[] files = dir.listFiles();
for (File f : files) {
System.out.println(f.getName());
}
}
删除和重命名功能
boolean delete(); // 删除文件或空目录
boolean renameTo(File dest); // 重命名或移动文件
// 注意:delete()方法
// 1. 删除目录时,目录必须为空
// 2. 删除操作不进回收站
// 3. 返回布尔值表示删除是否成功
二、IO流体系结构
1. IO流分类
按数据流向分:
输入流:读取数据(从文件/网络到内存)
输出流:写入数据(从内存到文件/网络)
按数据类型分:
字节流:以字节为单位(8位),可处理所有类型文件
字符流:以字符为单位(16位),只能处理文本文件
按功能分:
节点流:直接从数据源/目的地读写
处理流(包装流):对节点流进行包装,提供缓冲等功能
2. 完整体系结构
字节流(Byte Streams - 处理所有类型文件)
InputStream(抽象类)
├─ FileInputStream(文件字节输入流)
├─ ByteArrayInputStream(字节数组输入流)
├─ FilterInputStream(过滤流)
│ ├─ BufferedInputStream(缓冲字节输入流)
│ ├─ DataInputStream(数据输入流)
│ └─ PushbackInputStream(回退输入流)
├─ ObjectInputStream(对象输入流)
├─ PipedInputStream(管道输入流)
└─ SequenceInputStream(序列输入流)
OutputStream(抽象类)
├─ FileOutputStream(文件字节输出流)
├─ ByteArrayOutputStream(字节数组输出流)
├─ FilterOutputStream(过滤流)
│ ├─ BufferedOutputStream(缓冲字节输出流)
│ ├─ DataOutputStream(数据输出流)
│ └─ PrintStream(打印流)
├─ ObjectOutputStream(对象输出流)
└─ PipedOutputStream(管道输出流)
字符流(Character Streams - 处理文本文件)
Reader(抽象类)
├─ FileReader(文件字符输入流)
├─ InputStreamReader(字节流转字符流)
│ └─ BufferedReader(缓冲字符输入流)
├─ CharArrayReader(字符数组输入流)
├─ StringReader(字符串输入流)
├─ PipedReader(管道字符输入流)
└─ FilterReader
└─ PushbackReader(回退字符输入流)
Writer(抽象类)
├─ FileWriter(文件字符输出流)
├─ OutputStreamWriter(字节流转字符流)
│ └─ BufferedWriter(缓冲字符输出流)
├─ CharArrayWriter(字符数组输出流)
├─ StringWriter(字符串输出流)
├─ PipedWriter(管道字符输出流)
└─ FilterWriter
└─ PrintWriter(打印字符流)
三、字节流详解
1. InputStream(抽象类)
核心方法:
int read(); // 读取一个字节,返回-1表示结束
int read(byte[] b); // 读取到字节数组,返回读取字节数
int read(byte[] b, int off, int len); // 读取指定长度到字节数组
void close(); // 关闭流
int available(); // 返回可读字节数
long skip(long n); // 跳过n个字节
void mark(int readlimit); // 标记当前位置
void reset(); // 重置到标记位置
boolean markSupported(); // 是否支持标记
2. FileInputStream
// 构造方法
FileInputStream(File file)
FileInputStream(String name)
FileInputStream(FileDescriptor fdObj)
// 示例1:读取单个字节
try (FileInputStream fis = new FileInputStream("test.txt")) {
int data;
while ((data = fis.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
// 示例2:读取到字节数组(推荐,效率高)
try (FileInputStream fis = new FileInputStream("test.txt")) {
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
System.out.println(new String(buffer, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}
3. OutputStream(抽象类)
核心方法:
void write(int b); // 写入一个字节
void write(byte[] b); // 写入字节数组
void write(byte[] b, int off, int len); // 写入字节数组的一部分
void close(); // 关闭流
void flush(); // 刷新缓冲区
4. FileOutputStream
// 构造方法
FileOutputStream(File file)
FileOutputStream(File file, boolean append) // append=true表示追加
FileOutputStream(String name)
FileOutputStream(String name, boolean append)
// 示例1:写入单个字节
try (FileOutputStream fos = new FileOutputStream("output.txt")) {
String str = "Hello, World!";
for (char c : str.toCharArray()) {
fos.write(c);
}
} catch (IOException e) {
e.printStackTrace();
}
// 示例2:写入字节数组
try (FileOutputStream fos = new FileOutputStream("output.txt", true)) {
String str = "Hello, World!\n";
fos.write(str.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
5. 字节流文件复制
// 基本复制
try (FileInputStream fis = new FileInputStream("source.jpg");
FileOutputStream fos = new FileOutputStream("copy.jpg")) {
byte[] buffer = new byte[8192]; // 8KB缓冲区
int len;
while ((len = fis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
System.out.println("文件复制完成");
} catch (IOException e) {
e.printStackTrace();
}
四、字符流详解
1. Reader(抽象类)
核心方法:
int read(); // 读取一个字符
int read(char[] cbuf); // 读取到字符数组
int read(char[] cbuf, int off, int len);
void close();
long skip(long n);
boolean ready(); // 是否准备好读取
void mark(int readAheadLimit);
void reset();
boolean markSupported();
2. FileReader
// 构造方法
FileReader(File file)
FileReader(String fileName)
FileReader(FileDescriptor fd)
// 示例
try (FileReader fr = new FileReader("test.txt")) {
char[] buffer = new char[1024];
int len;
while ((len = fr.read(buffer)) != -1) {
System.out.println(new String(buffer, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}
3. Writer(抽象类)
核心方法:
void write(int c); // 写入一个字符
void write(char[] cbuf); // 写入字符数组
void write(char[] cbuf, int off, int len);
void write(String str); // 写入字符串
void write(String str, int off, int len);
void close();
void flush(); // 刷新缓冲区
4. FileWriter
// 构造方法
FileWriter(File file)
FileWriter(File file, boolean append)
FileWriter(String fileName)
FileWriter(String fileName, boolean append)
FileWriter(FileDescriptor fd)
// 示例
try (FileWriter fw = new FileWriter("output.txt", true)) {
fw.write("Hello, World!\n");
fw.write("这是第二行\n");
fw.flush(); // 立即刷新缓冲区
} catch (IOException e) {
e.printStackTrace();
}
五、处理流(包装流)
1. 缓冲流
特点: 自带缓冲区,提高读写效率
BufferedInputStream
// 构造方法
BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in, int size) // 指定缓冲区大小
// 示例
try (BufferedInputStream bis = new BufferedInputStream(
new FileInputStream("largefile.dat"))) {
byte[] buffer = new byte[8192];
int len;
while ((len = bis.read(buffer)) != -1) {
// 处理数据
}
} catch (IOException e) {
e.printStackTrace();
}
BufferedOutputStream
// 构造方法
BufferedOutputStream(OutputStream out)
BufferedOutputStream(OutputStream out, int size)
// 示例
try (BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("output.dat"))) {
byte[] data = "Hello".getBytes();
bos.write(data);
bos.flush(); // 确保数据写入
} catch (IOException e) {
e.printStackTrace();
}
BufferedReader
// 构造方法
BufferedReader(Reader in)
BufferedReader(Reader in, int sz)
// 特有方法
String readLine(); // 读取一行,返回null表示结束
// 示例:逐行读取
try (BufferedReader br = new BufferedReader(
new FileReader("test.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
BufferedWriter
// 构造方法
BufferedWriter(Writer out)
BufferedWriter(Writer out, int sz)
// 特有方法
void newLine(); // 写入换行符,跨平台
// 示例
try (BufferedWriter bw = new BufferedWriter(
new FileWriter("output.txt"))) {
bw.write("第一行");
bw.newLine(); // 跨平台换行
bw.write("第二行");
bw.flush();
} catch (IOException e) {
e.printStackTrace();
}
2. 转换流
作用: 字节流和字符流之间的桥梁
InputStreamReader
// 构造方法
InputStreamReader(InputStream in)
InputStreamReader(InputStream in, String charsetName) // 指定编码
InputStreamReader(InputStream in, Charset cs)
// 示例:解决乱码问题
try (InputStreamReader isr = new InputStreamReader(
new FileInputStream("test.txt"), "GBK")) {
char[] buffer = new char[1024];
int len;
while ((len = isr.read(buffer)) != -1) {
System.out.println(new String(buffer, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}
OutputStreamWriter
// 构造方法
OutputStreamWriter(OutputStream out)
OutputStreamWriter(OutputStream out, String charsetName)
OutputStreamWriter(OutputStream out, Charset cs)
// 示例
try (OutputStreamWriter osw = new OutputStreamWriter(
new FileOutputStream("output.txt"), "UTF-8")) {
osw.write("Hello, 世界!");
} catch (IOException e) {
e.printStackTrace();
}
3. 数据流
作用: 读写基本数据类型
DataInputStream
try (DataInputStream dis = new DataInputStream(
new FileInputStream("data.dat"))) {
int intValue = dis.readInt();
double doubleValue = dis.readDouble();
boolean boolValue = dis.readBoolean();
String strValue = dis.readUTF();
} catch (IOException e) {
e.printStackTrace();
}
DataOutputStream
try (DataOutputStream dos = new DataOutputStream(
new FileOutputStream("data.dat"))) {
dos.writeInt(100);
dos.writeDouble(3.14);
dos.writeBoolean(true);
dos.writeUTF("Hello");
} catch (IOException e) {
e.printStackTrace();
}
4. 对象流
作用: 序列化和反序列化对象
ObjectOutputStream
// 序列化
class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
// 构造方法、getter、setter省略
}
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("person.dat"))) {
Person person = new Person("张三", 20);
oos.writeObject(person);
} catch (IOException e) {
e.printStackTrace();
}
ObjectInputStream
// 反序列化
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("person.dat"))) {
Person person = (Person) ois.readObject();
System.out.println(person.getName());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
5. 打印流
特点: 不会抛出IOException,自动flush
PrintStream
// System.out就是PrintStream
PrintStream ps = new PrintStream("log.txt");
ps.println("日志信息");
ps.printf("当前时间:%tF %<tT%n", new Date());
ps.close();
PrintWriter
try (PrintWriter pw = new PrintWriter(
new FileWriter("output.txt"))) {
pw.println("第一行");
pw.printf("价格:%.2f元%n", 99.99);
} catch (IOException e) {
e.printStackTrace();
}
六、NIO.2(JDK7+)
1. Path接口
// 创建Path
Path path1 = Paths.get("D:/test/test.txt");
Path path2 = Paths.get("D:", "test", "test.txt");
Path path3 = FileSystems.getDefault().getPath("D:/test/test.txt");
// 常用方法
System.out.println(path1.getFileName()); // 文件名
System.out.println(path1.getParent()); // 父目录
System.out.println(path1.getRoot()); // 根目录
System.out.println(path1.getNameCount()); // 名称元素数量
System.out.println(path1.getName(0)); // 第i个名称元素
2. Files工具类
// 文件操作
Path source = Paths.get("source.txt");
Path target = Paths.get("target.txt");
// 复制文件
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
// 移动文件
Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);
// 删除文件
Files.deleteIfExists(target);
// 判断文件属性
boolean exists = Files.exists(path);
boolean isDir = Files.isDirectory(path);
boolean isHidden = Files.isHidden(path);
boolean isReadable = Files.isReadable(path);
boolean isWritable = Files.isWritable(path);
// 读取文件
byte[] bytes = Files.readAllBytes(path);
List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
// 写入文件
Files.write(path, "内容".getBytes());
Files.write(path, Arrays.asList("第一行", "第二行"),
StandardCharsets.UTF_8);
// 遍历目录
try (Stream<Path> stream = Files.list(Paths.get("D:/test"))) {
stream.forEach(System.out::println);
}
七、IO流使用总结
1. 选择流的准则
文本文件:使用字符流
二进制文件:使用字节流
需要缓冲:使用缓冲流
需要特定编码:使用转换流
读写基本数据类型:使用数据流
读写对象:使用对象流
需要序列化:实现Serializable接口
2. 性能优化建议
// 1. 使用缓冲区
try (BufferedInputStream bis = new BufferedInputStream(
new FileInputStream("file.dat"));
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("copy.dat"))) {
// 处理逻辑
}
// 2. 选择合适的缓冲区大小(通常8KB-32KB)
byte[] buffer = new byte[8192]; // 8KB
// 3. 使用try-with-resources自动关闭资源
try (FileInputStream fis = new FileInputStream("file.txt")) {
// 自动关闭
}
// 4. 批量读写,减少IO操作次数
3. 编码问题处理
// 指定编码读取
try (BufferedReader br = new BufferedReader(
new InputStreamReader(
new FileInputStream("file.txt"),
"UTF-8"))) {
// 读取
}
// 指定编码写入
try (BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream("file.txt"),
"UTF-8"))) {
// 写入
}
4. 常见问题解决
// 文件复制优化
public static void copyFile(String src, String dest) throws IOException {
try (InputStream in = new BufferedInputStream(
new FileInputStream(src));
OutputStream out = new BufferedOutputStream(
new FileOutputStream(dest))) {
byte[] buffer = new byte[8192];
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
out.flush();
}
}
// 读取大文件
public static void readLargeFile(String filename) throws IOException {
try (BufferedReader br = new BufferedReader(
new FileReader(filename))) {
String line;
while ((line = br.readLine()) != null) {
// 处理每一行
}
}
}
八、常见面试题
-
File类的作用是什么?
-
字节流和字符流的区别?
-
为什么要使用缓冲流?
-
如何选择IO流?
-
序列化和反序列化是什么?
-
如何解决中文乱码问题?
-
try-with-resources的好处?
-
NIO和传统IO的区别?
-
如何提高IO性能?
-
Files类相比File类有什么优势?
这个IO流总结详细介绍了Java IO体系的所有重要类和方法,包括文件操作、各种流的使用、性能优化和常见问题的解决方案,适合发布到CSDN等技术博客平台。
更多推荐



所有评论(0)