【JAVASE | 第十四篇】IO流:普通流和特殊流总结
前言
这篇内容主要写普通io流的相关内容。
主要包括:
- 普通字节流
- 普通字符流
- 转换流
- 打印流
- Commons-IO 工具类
这些内容虽然没有缓冲流那么“亮眼”,但它们才是整个 IO 体系中最基础、最核心的部分。
所以这篇文章,我们就把它们统一整理一下。
引入
如果说缓冲流是在普通流外面加了一层“加速器”,那么普通流就是最基础的骨架,而特殊流则是在这个骨架基础上增加了一些额外功能,比如:
- 编码转换
- 便捷打印
- 工具类封装
所以这一篇的重点,就是搞清楚:
普通流负责基础读写,特殊流负责补充功能。
一、普通字节输入流 FileInputStream
1.一次性读写一个
项目中的代码如下:
InputStream input = new FileInputStream("day03-flie-io/src/xl2");
int b;
while((b = input.read()) != -1){
System.out.print((char)b);
}
这种写法最容易理解,但是问题也很明显:
- 性能比较差
- 读取中文时可能乱码
因为字节流读到的只是字节,而不是字符。
一次读取多个字节
写法如下:
InputStream input = new FileInputStream("day03-flie-io/src/xl3");
byte[] bytes = new byte[3];
int a;
while((a = input.read(bytes)) != -1){
String string = new String(bytes, 0, a);
System.out.println(string);
}
这种方式比一个字节一个字节读取更快。
但是如果读取的是中文文本,仍然可能出现乱码问题。
原因很简单:
字节流只负责读取原始字节,不负责按照正确编码把它翻译成字符。
一次性读取全部内容
项目中的代码如下:
InputStream is = new FileInputStream("day03-flie-io/src/xl4");
byte[] bytes = is.readAllBytes();
String s = new String(bytes);
System.out.println(s);
这种方式的优点是简单,适合小文件。
但是如果文件很大,就不推荐这样做,因为会一次性占用较多内存。
FileInputStream 的特点总结
FileInputStream 的几个关键特点如下:
- 以字节为单位读取数据
- 适合处理任意类型文件
- 适合图片、音频、视频、压缩包等文件
- 读取文本时可能出现乱码
- 数组读取比单字节读取更常用
所以它更适合处理“文件本身”,而不适合负责“文本理解”。
二、普通字节输出流 FileOutputStream
1. 基本使用
OutputStream out = new FileOutputStream("day03-file-io/src/xiaole1", true);
out.write(97);
out.write('b');
out.write("\r\n".getBytes());
byte[] bytes = "我是".getBytes();
out.write(bytes);
out.write(bytes, 0, 3);
out.close();
2. 核心特点
(1)可以写单个字节,也可以写字节数组
常见方法有:
write(int b)
write(byte[] bytes)
write(byte[] bytes, int off, int len)
(2)可以选择覆盖写或追加写
new FileOutputStream(path) // 覆盖
new FileOutputStream(path, true) // 追加
这一点在写日志、补充文本内容时很常用。
(3)换行需要自己处理
因为字节流操作的是字节,所以想换行时要自己写:
out.write("\r\n".getBytes());
这也是字节流处理文本时不如字符流方便的原因之一。
三、普通字符输入流 FileReader
1. 基本使用
Reader reader = new FileReader("day03-File-io\\src\\zifuxiaole1");
char[] c = new char[3];
int len;
while((len = reader.read(c)) != -1) {
String string = new String(c, 0, len);
System.out.print(string);
}
2. FileReader 的特点
- 以字符为单位读取
- 更适合读取文本文件
- 读取中文比普通字节流更自然
- 不适合读取图片、视频等二进制文件
所以 FileReader 的定位很明确:
专门处理文本,不处理所有文件。
四、普通字符输出流 FileWriter
1. 基本使用
Writer fw = new FileWriter("day03-File-io/src/itheima/FileWriterDemo8/xiaole-out1", true);
fw.write('a');
fw.write(98);
fw.write("Java");
fw.write("\r\n");
char[] chars = "java".toCharArray();
fw.write(chars);
fw.write(chars, 1, 2);
2. FileWriter 的特点
- 写文本更方便
- 可以写字符、字符串、字符数组
- 更适合处理纯文本内容
- 同样支持追加写入
- 多行内容通常需要自己写换行符
和 FileOutputStream 相比,FileWriter 更适合文本。
和 BufferedWriter 相比,FileWriter 更基础。
五、普通流和缓冲流的关系
这个地方特别容易混。
其实可以这样理解:
FileInputStream、FileOutputStream、FileReader、FileWriter是普通流BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter是增强流
也就是说:
普通流负责“能读能写”,缓冲流负责“读写更快、更方便”。
六、特殊流之一:转换流 InputStreamReader
1. 基本使用
InputStream inputStream = new FileInputStream("day03-File-io\\src\\zifuxiaole3");
Reader isr = new InputStreamReader(inputStream, "GBK");
BufferedReader reader = new BufferedReader(isr);
2. 为什么需要转换流
前面我们已经提到过,字节流读取文本时可能乱码。
根本原因就在于:字节流不认识编码。
而转换流的作用就是:
把字节流按照指定编码转换成字符流。
比如这句代码:
new InputStreamReader(inputStream, "GBK")
就是告诉程序:
“这个文件里的字节,请按 GBK 编码方式转换成字符。”
3. InputStreamReader 的特点
- 本质上是桥梁流
- 连接字节流和字符流
- 能解决不同编码下的乱码问题
- 在中文文本读取中非常常见
所以当我们处理:
- UTF-8 文件
- GBK 文件
- 网络传输文本
- 文件导入内容
时,转换流是很有必要的。
七、特殊流之二:打印流 PrintWriter
1. 基本使用
PrintWriter ps = new PrintWriter(
new FileOutputStream("day03-File-io/src/itheima/bufferedandinputoutput/Demo13inputstreamreader/printtest1", true)
);
ps.println(97);
ps.println("我");
ps.println('你');
ps.println(true);
2. PrintWriter 的特点
(1)输出更方便
普通流输出内容时,经常要考虑字节、字符、编码等问题。
而打印流直接提供了:
print()
println()
所以写起来更顺手。
(2)可以直接打印多种数据类型
项目中就打印了:
- 整数
- 字符串
- 字符
- 布尔值
这说明 PrintWriter 的通用性很强。
(3)适合输出格式化文本
打印流常用于:
- 日志输出
- 文本结果输出
- 报表输出
- 控制台打印
在这类场景中,它比普通输出流更方便。
八、特殊内容补充:Commons-IO 工具类
FileUtils.copyFile(new File("day03-File-io\\src\\xl2"), new File("day03-File-io\\src\\xl11"));
FileUtils.forceDelete(new File("day03-File-io\\src\\xl11"));
这里用到了 org.apache.commons.io.FileUtils。
它不是 JDK 原生流类,但它是一个很实用的 IO 工具类库。
1. 它的特点
- 封装了很多常见文件操作
- 代码更简洁
- 减少了手动写流复制的重复代码
2. 常见用途
- 复制文件
- 删除文件
- 复制目录
- 读取文件
- 写入文件
可以把它理解成:
在 IO 流基础上的一个工具箱。
九、普通流和特殊流怎么选
这里我直接做一个简单总结。
1. 处理任意文件
优先考虑:
FileInputStreamFileOutputStreamBufferedInputStreamBufferedOutputStream
2. 处理文本文件
优先考虑:
FileReaderFileWriterBufferedReaderBufferedWriter
3. 涉及编码转换
优先考虑:
InputStreamReader
4. 需要方便打印
优先考虑:
PrintWriter
5. 想快速完成常见文件操作
可以考虑:
FileUtils
总结
这次把io流中除了缓冲流之外的剩余内容也梳理了一遍,整个 IO 流体系就更完整了。
可以这样理解:
- 普通流是基础
- 缓冲流是增强
- 转换流是桥梁
- 打印流是便捷输出
- Commons-IO 是工具封装
最后再总结一下它们各自的定位:
FileInputStream / FileOutputStream:处理任意文件FileReader / FileWriter:处理文本文件BufferedXXX:提升效率、增强体验InputStreamReader:解决编码转换问题PrintWriter:输出更方便FileUtils:简化常见文件操作
如果说缓冲流解决的是“快不快”,
那么普通流和特殊流解决的就是“能不能做、怎么做更合适”。
更多推荐


所有评论(0)