本文基于 Java 原生 IO 流,从最基础的字节流到字符流,再到实战案例(如文件夹拷贝、文件加密等)进行逐步深入讲解。适合有一定 Java 基础、希望掌握文件读写操作的。
一、前言
Java IO(输入输出)是我们日常开发中必不可少的一部分。无论是读写文件、传输数据、处理日志,IO 都是底层支持。在这篇博客中,我们将基于实际代码案例,从 FileOutputStream
、FileInputStream
到 FileReader
、FileWriter
全面解析 Java IO 的用法与底层原理,并完成以下内容:
文件写入(字节/字符流)
文件读取
文件拷贝(大文件/小文件/文件夹)
编码解码与乱码问题
文件加密与解密
在对文件进行读写操作时,必须要开启一个流,这个流是以你的程序角度的,比如你要向文件写入数据,那么就可以开输出流(OutputStream),从文件读取数据,就可以开启输入流(InputStream)。
二、字节输出流:FileOutputStream
1. 写一个字节:write(int b)
FileOutputStream fos = new FileOutputStream("a.txt");
fos.write('a');
fos.close();
写入单个字节(ASCII 字符)。
2. 写入字节数组:write(byte[] b)
byte[] bytes = {97, 98, 99};
fos.write(bytes);
3. 写入部分字节:write(byte[] b, int off, int len)
fos.write(bytes, 1, 2); // 从索引1开始写两个字节(b和c)
注意事项
默认覆盖已有内容。
可通过构造函数加参数启用追加模式:
new FileOutputStream("a.txt", true);
三、字节输入流:FileInputStream
1. 读取一个字节:read()
FileInputStream fis = new FileInputStream("a.txt");
int b = fis.read();
System.out.println(b);
2. 循环读取所有字节
int b;
while ((b = fis.read()) != -1) {
System.out.print((char) b);
}
3. 读取字节数组:read(byte[] buffer)
byte[] buffer = new byte[2];
int len = fis.read(buffer);
System.out.println(new String(buffer, 0, len));
四、文件拷贝实战
小文件拷贝
int b;
while ((b = fis.read()) != -1) {
fos.write(b);
}
大文件拷贝(使用缓冲数组)
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
try-with-resources 简化关闭资源
try(FileInputStream fis = new FileInputStream("a.txt");
FileOutputStream fos = new FileOutputStream("b.txt")) {
...
}
五、字符集编码与乱码问题
字符集基础
编码类型 | 特点 |
---|---|
ASCII | 单字节英文编码 |
GBK | 双字节中文编码 |
UTF-8 | 可变长度,英文1字节,中文3字节 |
Unicode | Java默认字符集,多数使用UTF-16 |
为什么会乱码?
字节读取不完整一个中文字符
编码与解码方式不一致
编码与解码示例
String str = "你好世界";
byte[] gbk = str.getBytes("GBK");
byte[] utf8 = str.getBytes("UTF-8");
System.out.println(new String(gbk, "GBK")); // 正确
System.out.println(new String(utf8, "UTF-8")); // 正确
六、字符流读写(FileReader / FileWriter)
字符流其实是在字节流的基础上进行了封装,字节流每次单个字节读取,会导致读取到的汉字不完整而出现乱码,而字符流可以很好解决这个问题: 默认单个字节地读取,当遇到汉字时,就每次三个字节地读取(UTF-8)
字符输入流 FileReader
FileReader fr = new FileReader("a.txt");
int ch;
while ((ch = fr.read()) != -1) {
System.out.println((char) ch);
}
字符输出流 FileWriter
FileWriter fw = new FileWriter("a.txt");
fw.write("我是你爹");
fw.close();
默认有缓冲机制
FileReader
内部有一个 8192 字节缓冲区FileWriter
会缓存数据,写入文件需flush()
或close()
七、实战项目:文件夹拷贝
实现文件夹递归拷贝
public void copydir(File src, File dest) throws IOException {
File[] files = src.listFiles();
if (files == null) return;
for (File file : files) {
if (file.isFile()) {
try (FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(new File(dest, file.getName()))) {
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
}
} else {
copydir(file, new File(dest, file.getName()));
}
}
}
八、实战项目:文件加密器
通过位运算进行简单加密(可以自定义加密规则):
FileInputStream fis = new FileInputStream("a.txt");
FileOutputStream fos = new FileOutputStream("ency.txt");
int b;
while ((b = fis.read()) != -1) {
fos.write(b ^ 123); // 加密:异或操作
}
九、总结
通过本篇博客你学到了:
- Java 文件读写的三种方式
- 编码解码、乱码问题处理
- 实战项目(拷贝/加密)演练
- 字符流 vs 字节流的底层机制差异