第七章 输入输出流
第二节 文件读写操作
概述
文件读写操作是Java程序设计中非常重要的基础内容,尤其在全国计算机等级考试二级Java语言程序设计中,占有举足轻重的地位。本节将系统讲解Java中如何进行文件的读取与写入操作,涵盖文件输入流、文件输出流的使用,字符流与字节流的区别与应用,文件操作的基本流程,异常处理,以及性能优化等内容。
学习目标:
- 理解文件读写的基本概念和原理
- 掌握使用Java标准API进行文件读写的具体方法
- 能够编写稳定、健壮的文件读写程序
- 熟悉常见的文件读写错误及其解决方案
- 了解文件读写在实际项目中的应用场景
核心概念
文件(File)
- 计算机中用于持久存储数据的基本单位。
- Java中的
java.io.File类表示文件和目录的抽象路径名。
输入流(InputStream)
- 用于读取数据的流,数据源可以是文件、网络等。
- 以字节为单位读取数据的流。
输出流(OutputStream)
- 用于写出数据的流,数据目标可以是文件、网络等。
- 以字节为单位写出数据的流。
字符流(Reader/Writer)
- 针对字符的输入输出流,基于字节流实现,支持字符编码。
缓冲流(BufferedReader/BufferedWriter/BufferedInputStream/BufferedOutputStream)
- 提供缓冲功能,提高读写效率。
文件读写的异常处理
- 文件操作常伴随IO异常,需通过try-catch-finally或try-with-resources管理资源。
原理分析
1. 文件读写的工作原理
文件读写操作本质上是程序和磁盘存储设备之间的数据传输过程。Java通过流(Stream)抽象了数据的传输过程,使程序无需关心底层硬件细节,只需操作流即可完成数据的输入输出。
- 输入流负责从文件中读取数据,通常按字节或字符逐个读取。
- 输出流负责向文件写入数据,按字节或字符逐个写入。
文件读写过程通常包括:
- 创建文件对象,指定文件路径
- 打开文件输入/输出流
- 循环读取或写入数据
- 关闭流,释放资源
2. 字节流与字符流的区别
| 特性 | 字节流(InputStream/OutputStream) | 字符流(Reader/Writer) |
|---|---|---|
| 处理数据类型 | 处理字节(8位),适合所有类型文件(如图片、音频) | 处理字符(16位),适合文本文件 |
| 编码问题 | 不处理编码,需要程序自行转换字符编码 | 自动处理字符编码,方便文本读写 |
| 继承结构 | 基于InputStream和OutputStream类 | 基于Reader和Writer类 |
3. 缓冲流的作用
缓冲流内部维护一个缓冲区,减少每次读写操作对硬盘的直接访问,显著提高效率。常用的缓冲流有BufferedReader、BufferedWriter(字符流缓冲)和BufferedInputStream、BufferedOutputStream(字节流缓冲)。
4. 异常处理和资源管理
文件操作会抛出IOException异常,必须通过异常处理机制捕获。同时,打开的流资源必须被关闭,避免资源泄漏。Java 7引入的try-with-resources语法简化了资源关闭操作。
详细内容
1. 文件读取操作
Java读取文件主要使用FileInputStream(字节流)和FileReader(字符流)。
使用FileInputStream读取文件
FileInputStream fis = null;
try {
fis = new FileInputStream("data.txt");
int b;
while ((b = fis.read()) != -1) {
System.out.print((char) b); // 按字节读取,强制转换为字符输出
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
缺点:读取效率较低,且不适合直接读取文本文件中的字符。
使用BufferedReader读取文本文件
try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
优点:按行读取,效率高,使用简单,适合文本文件。
2. 文件写入操作
Java写文件常用FileOutputStream和FileWriter。
使用FileOutputStream写入文件
try (FileOutputStream fos = new FileOutputStream("output.txt")) {
String content = "Hello, Java File IO!";
fos.write(content.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
使用BufferedWriter写文件(推荐)
try (BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"))) {
bw.write("第一行内容");
bw.newLine();
bw.write("第二行内容");
} catch (IOException e) {
e.printStackTrace();
}
3. 文件复制示例
复制文件是文件读写操作的典型应用,考察字节流的读写。
public static void copyFile(String srcPath, String destPath) {
try (FileInputStream fis = new FileInputStream(srcPath);
FileOutputStream fos = new FileOutputStream(destPath)) {
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
4. 文件追加写入
Java写文件默认会覆盖文件内容,若需要追加写入,需要构造FileWriter时指定追加模式。
try (FileWriter fw = new FileWriter("file.txt", true);
BufferedWriter bw = new BufferedWriter(fw)) {
bw.write("追加内容");
bw.newLine();
} catch (IOException e) {
e.printStackTrace();
}
5. 文件路径和文件对象
通过java.io.File类可以方便地表示文件和目录,支持判断文件是否存在、创建目录、删除文件等操作。
File file = new File("test.txt");
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
实例分析
案例一:读取文本文件统计行数
背景:统计文件中有多少行文本。
代码分析:
- 使用
BufferedReader按行读取 - 计数器统计读取的行数
public static int countLines(String filePath) {
int lines = 0;
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
while (br.readLine() != null) {
lines++;
}
} catch (IOException e) {
e.printStackTrace();
}
return lines;
}
结论:使用字符缓冲流按行读取,代码简洁高效。
案例二:大文件复制性能对比
背景:比较使用缓冲流与不使用缓冲流复制大文件的性能差异。
分析:
- 不使用缓冲流,逐字节读取写入,性能低下。
- 使用缓冲流,批量读写,显著提升效率。
结论:缓冲流是处理大文件读写时的首选。
案例三:日志文件追加写入
背景:向日志文件追加写入日志信息,保留原有内容。
实现:
- 使用
FileWriter的追加模式 - 结合
BufferedWriter写入多行内容
代码示例:
public static void appendLog(String logFile, String logContent) {
try (BufferedWriter bw = new BufferedWriter(new FileWriter(logFile, true))) {
bw.write(logContent);
bw.newLine();
} catch (IOException e) {
e.printStackTrace();
}
}
结论:追加写入文件,防止覆盖,适合日志处理。
常见误区
不关闭流资源
- 错误:忘记关闭输入输出流,导致资源泄漏。
- 正确:使用try-with-resources或finally块关闭流。
错误使用字符流读取二进制文件
- 错误:用
FileReader读取图片、音频等非文本文件。 - 正确:用字节流
FileInputStream处理二进制文件。
- 错误:用
忽略字符编码问题
- 错误:读取或写入文本文件时未指定编码,导致乱码。
- 正确:使用
InputStreamReader、OutputStreamWriter指定编码。
文件路径错误
- 错误:硬编码路径,导致跨平台或路径不存在问题。
- 正确:使用相对路径或
File类方法处理路径。
写文件时未开启追加模式
- 错误:写入时默认覆盖文件内容,丢失数据。
- 正确:需要追加时,构造
FileWriter时传入true参数。
应用场景
配置文件读取
- 程序启动时读取配置参数文件,初始化环境。
日志文件管理
- 程序运行过程中记录日志,便于后续排查问题。
数据备份与恢复
- 通过文件复制实现数据备份,保障数据安全。
文件上传下载功能
- 服务器端处理用户上传的文件,保存至磁盘;下载时读取文件并输出。
文本处理程序
- 读取文本文件内容进行分析、统计或转换。
知识拓展
Java NIO(New IO)
- Java 1.4引入的非阻塞IO,提供
FileChannel、ByteBuffer等,性能优于传统IO,适合大文件和高性能需求。
- Java 1.4引入的非阻塞IO,提供
文件路径处理
- Java 7引入
java.nio.file.Path和Files,简化文件操作,支持符号链接、文件属性操作。
- Java 7引入
对象序列化
- 将对象写入文件,实现持久化存储。
异步文件IO
- Java 7的异步文件通道,支持异步读写。
总结回顾
本节重点围绕Java文件的读写操作展开,涵盖了:
- 文件读写的基本概念及Java中的流模型
- 字节流与字符流的区别与使用场景
- 常用的文件输入输出类(FileInputStream, FileOutputStream, FileReader, FileWriter)
- 缓冲流的作用及使用方法,提高读写效率
- 文件复制、追加写入等典型操作示例
- 文件操作中的异常处理与资源管理
- 常见错误及纠正方法,帮助避免常见坑点
- 实际应用场景及拓展知识,增强理解与应用能力
通过本节学习,考生应能熟练编写文件读写程序,理解文件操作的底层原理,为后续复杂IO操作和Java程序设计打下坚实基础。
【完整代码示例】
import java.io.*;
public class FileReadWriteDemo {
// 读取文件内容并打印
public static void readFile(String filePath) {
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 写入内容到文件
public static void writeFile(String filePath, String content, boolean append) {
try (BufferedWriter bw = new BufferedWriter(new FileWriter(filePath, append))) {
bw.write(content);
bw.newLine();
} catch (IOException e) {
e.printStackTrace();
}
}
// 文件复制
public static void copyFile(String src, String dest) {
try (FileInputStream fis = new FileInputStream(src);
FileOutputStream fos = new FileOutputStream(dest)) {
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String filePath = "test.txt";
writeFile(filePath, "第一行内容", false);
writeFile(filePath, "第二行内容", true);
readFile(filePath);
copyFile(filePath, "copy_test.txt");
}
}
通过实践和理解以上内容,考生能够扎实掌握Java文件读写操作,顺利应对全国计算机等级考试二级Java语言程序设计的相关考题。