IO流
本质:就是用来传输数据的
- 作用: 读写
- 数据的持久化,利用的就是写的功能
文章目录
1.IO流的特点
-
数据的传输必须经过内存
-
从外界到内存叫做输入流
-
从内存到外界叫做输出流
-
流编程关心三要素
-
数据源: 从哪里到内存
-
目的地: 从内存到哪里去
-
交通工具: 选择对应的流相关的类
-
2.字节流
字节流是万能流,读写纯二进制文件必须用字节流 【视频 音频 图片】
文本文件 【java txt html css js xml...】
InputStream
FileInputStream
BufferedInputStream
OutputStream
FileOutputStream
BufferedOutputStream
2.1输出流
输出流的特点: 如果输出流对应的路径没有真实的文件,会自动创建
常用方法:
说明 | |
---|---|
void close() | 关闭此输出流并释放与此流有关的所有系统资源。 |
void flush() | 刷新此输出流并强制写出所有缓冲的输出字节。 缓冲区【字节数组 字符数组 容器】刷新到外界 |
void write(byte[] b) | 将 b.length 个字节从指定的 byte 数组写入此输出流。 |
void write(byte[] b, int off, int len) | 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。 |
abstract void write(int b) | 将指定的字节写入此输出流。 |
2.2输入流
- 单字节
说明 | |
---|---|
abstract int read() | 从输入流中读取数据的下一个字节。 |
特点:
- 每次读取一个字节,读取完之后,文件指针向后移动一个字节单位,准备读取下一个字节
- 际读取的内容,如果读取到文件末尾返回-1
- 方法返回的是读取内容
缺点:
- 效率太低
- 如果有中文可能乱码
- 数组
说明 | |
---|---|
int read(byte[] b) | 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。 |
int read(byte[] b, int off, int len) | 将输入流中最多 len 个数据字节读入 byte 数组。 |
特点:
-
一次性读取一个字节数组,放入到形参中
-
每读取一个字节数组,并且将文件指针指向下一个字节数组后的位置
-
方法返回的结果是实际读取的长度,读取到文件末尾返回-1
2.2.1读取原理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EBtlelf9-1574675065111)(E:\尚学堂\TYPORA_NOTES\16.3 IO流.assets\读取原理.png)]
2.3高效字节缓冲流
BufferedInputStream BufferedOutputStream
用法:
BufferedInputStream is = new BufferedInputStream(InputStream in);
//根据多态
InputStream inputStream = new FileInputStream();
//简化
BufferedInputStream is = new BufferedInputStream(new FileInputStream());
2.4注意事项
-
数据写入完成后记得调用**close()**方法关闭流对象
-
数据追加写入要使用如下构造方法
FileOutputStream(File file, boolean append)// 追加写入方式 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("fos.txt", true)); for (int i = 1; i <= 10; i++) { bos.write(("HelloWorld" + i).getBytes()); bos.write("\r\n".getBytes()); } bos.close();
-
不同的系统针对不同的换行符号识别是不一样的
例如:windows识别的换行符是\r\n,Linux识别的换行符是\n等等。
常见的一些高级记事本,是可以识别任意换行符号的。 -
数据写入中存在两个异常需要处理FileNotFoundException,IOException。
FileNotFoundException extends IOException -
多的"-1"问题
InputStream is = new FileInputStream("IODemo03.java"); int b = 0; //问题代码: //原因,多循环了 while(b != -1) { b = is.read();//当b显示的是最后后一个字符,while的条件是ture //进入循环后没有字符可以读取,返回-1并输出 System.out.print((char)b); } //正确代码 while((b = is.read()) != -1) { System.out.print((char)b); }
2.5字节流缺点:
-
如果人为的转换可能出现乱码 【字符的编码表有很多】
-
处理一些特殊字符【换行符】不方便
-
如果我想要读取文本文件中的某一行不方便【不能读行】
3.字符流
字符流是为了更好读写文本文件而引出的 (用记事本打开你能够读懂就是用字符流)
- Reader
InputStreamReader
FileReader
BufferedReader
- Writer
OutputStreamWriter
- FileWriter
BufferedWriter
3.1字符输出流(Writer)
Writer | 说明 |
---|---|
Writer append(char c) | 将指定字符添加到此 writer |
Writer append(CharSequence csq) | 将指定字符序列添加到此 writer |
Writer append(CharSequence csq, int start, int end) | 将指定字符序列的子序列添加到此 writer.Appendable |
abstract void close() | 关闭此流,但要先刷新它 |
abstract void flush() | 刷新该流的缓冲 |
void write(char[] cbuf) | 写入字符数组 |
abstract void write(char[] cbuf, int off, int len) | 写入字符数组的某一部分 |
void write(int c) | 写入单个字符 |
void write(String str) | 写入字符串 |
void write(String str, int off, int len) | 写入字符串的某一部分 |
3.2字符输入流 ( Reader )
Reader | 说明 |
---|---|
int read() | 读取单个字符 |
int read(char[] cbuf) | 将字符读入数组 |
abstract int read(char[] cbuf, int off, int len) | 将字符读入数组的某一部分 |
3.3转换流
InputStreamReader && OutputStreamWriter
-
本质是一个字符流
-
能够处理编码
-
能够将字节流转换成字符流
InputStreamReader isr = new InputStreamReader(new FileInputStream("charset.txt"), "utf-8");
char[] chs = new char[7];
int len = isr.read(chs);
System.out.println(new String(chs, 0, len));
osw.close();
isr.close();
Reader r = new InputStreamReader(new FileInputStream("IODemo03.java"));
3.4高效缓冲字符流
- BufferedReader
- readLine可以读取一行
- 提高字符流的效率
- BufferedWriter
- newLine能够适配不同操作系统的换行符
- 提高字符流的效率
private static void copy(String srcFileName, String descFileName) {
try (BufferedReader br = new BufferedReader(new FileReader(srcFileName));
BufferedWriter bw = new BufferedWriter(new FileWriter(descFileName))){
String line = null;
while((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
bw.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
4.close() & flash() 的区别
-
字节流是纯粹的二进制,所以可以不用flush,但是字符流需要将某些字节按照某种编码转换成字符,先读取到缓冲区,这个时候必须要flush
-
close方法来自于 AutoCloseable接口 【输入流和输出流都需要关闭】
如果是输入流,直接释放流资源
如果是输出流,先将所有的缓冲区中字节刷新到外界,再释放资源 -
flush来自于Flushable接口 【输出流】
输入流不需要flush
输出流表示将每次读取的内容从内存刷新到外界
5.异常类型
-
java.io.IOException: Stream Closed 流关闭之后不可以再进行读写
-
java.io.FileNotFoundException 文件不存在
6.编码、解码、编码表
编码: 将字符、字符串、流转换成 二进制 [ “c” --> “97” --> 1100001 ]
解码: 将二进制转换成对应的字符、字符串、流 [ 1100001 --> “97” --> “c” ]
编码表: 就是数字和字符对应的一张表
- 编码表有很多,常见的编码表:
-
ASCII 美国标准信息交换码
-
Unicode 国际标准码
-
UTF-8 最多用三个字节来表示一个字符。
-
ISO-8859-1 拉丁码表。欧洲码表。【文件服务器或者Tomcat7默认编码就是这个】
-
GB2312/GBK/GB18030 中文编码表。
-
Java平台中**默认采用的编码方式是GBK**。
-
6.1乱码原因
-
在文件读写的时候人为的转换
-
系统文件编码不一致
-
读取和写入的编码表不一致
-
url编码出现问题
6.2显示问题
视频:
- 字节流缺失字节,播放不了
- 字符流缺失可以播放
图片:
- 字节流图片缺失字节可能可以播放