IO流
一、概述
-
IO流也称为输入、输出流,就是用来读写数据的。
-
比如我们玩过的消消乐游戏,这个游戏需要将分数展示出来给玩家看,当玩家的下一次分数超过上一次分数的时候,需要将新分数存到内存中,这就是数据的读写操作。
I
表示intput
,是数据从硬盘文件读入到内存的过程,称之输入
——负责读;O
表示output
,是内存程序的数据从内存写出到硬盘文件的过程,称之输出
——负责写。
二、分类
-
按流的方向分
-
按流中的数据最小单位分为
三、总结流的四大类
- 字节输入流:以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中去的流称为字节输入流;
- 字节输出流:以内存为基准,把内存中的数据以字节写出到磁盘文件或网络中去的流称为字节输出流;
- 字符输入流:以内存为基准,来自磁盘文件/网络中的数据以字符的形式读入到内存中去的流称为字符输入流;
- 字符输出流:以内存为基准,把内存中的数据以字符写出到磁盘文件或网络中去的流称为字符输出流。
四、IO流体系
- 它们都是抽象类。
小结
1、IO流的作用是什么?
- 读写文件数据的
2、IO流是怎么划分的,大体分为几类?各自的作用是什么?
- 字节流:字节输入、输出流(读写字节数据的)
- 字符流:字符输入、输出流(读写字符数据的)
五、字节流的使用
1、文件字节输入流
- FileInputStream类:实现类
(1)作用
- 以内存为基准,把磁盘文件中的数据以字节的形式读取到内存中。
(2)构造器
构造器 | 说明 |
---|---|
public FileInputStream(File file) | 创建字节输入流管道与源文件对象接通 |
public FileInputStream(String pathname) | 创建字节输入流管道与源文件路径接通 |
(3)方法
方法名称 | 说明 |
---|---|
public int read() | 每次读取一个字节返回,如果字节已经没有可读的返回 -1 |
public int read(byte[] buffer) | 每次读取一个字节数组返回,如果字节已经没有可读的返回 -1 |
(4)每次读取一滴水
package com.app.d5_byte_stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
/**
目标:
学会字节流的使用一:文件字节输入流
每次读取一滴水
*/
public class FileInputStreamDemo01 {
public static void main(String[] args) throws Exception {
// 1、创建一个文件字节输入流管道与源文件接通
// 写法1
// InputStream is = new FileInputStream(new File("day10-file-io-app\\src\\data.txt"));
// 写法2:写法1的简化版,推荐使用
InputStream is = new FileInputStream("day10-file-io-app\\src\\data.txt");
// 2、读取一个字节返回(每次读取一滴水)
int b1 = is.read();
System.out.println(b1); // 编码
System.out.println((char) b1); // 字符
int b2 = is.read();
System.out.println(b2);
System.out.println((char) b2);
int b3 = is.read();
System.out.println(b3);
System.out.println((char) b3);
int b4 = is.read();
System.out.println(b4);
System.out.println((char) b4);
int b5 = is.read();
System.out.println(b5);
System.out.println((char) b5);
int b6 = is.read(); // 字节已经读完了,返回 -1
System.out.println(b6);
}
}
97
a
98
b
99
c
50
2
49
1
-1
Process finished with exit code 0
(5)每次读取一滴水的弊端
- 虽然写法更加优化了,但是依旧存在一个弊端!
- 弊端:假如文件中存在中文字,大家都知道:英文和数字只占1个字节,而中文占3个字节,如果一个一个的读取文件的数据,等读到中文的时候,就会出现中文乱码的情况!!
总结
1、文件字节输入流,每次读取一个字节的API是哪个?
public int read(){
...
}
2、每次读取一个字节存在什么问题?
- 性能较慢
- 读取中文字符输出无法避免乱码问题
(6)每次读取一个字节数组
package com.app.d5_byte_stream;
import java.io.FileInputStream;
import java.io.InputStream;
/**
目标:学会字节流的使用二:文件字节输入流
每次读取一桶水
*/
public class FileInputStreamDemo02 {
public static void main(String[] args) throws Exception {
// 1、创建一个文件字节输入流管道与源文件接通
InputStream is = new FileInputStream("day10-file-io-app/src/data02.txt");
// 2、创建一个byte类型的数组,作为桶,一次读取3滴水
byte[] buffer = new byte[3];
int len = is.read(buffer);
System.out.println("第一个桶读取了 " + len + " 个字节");
// 解码
String rs = new String(buffer);
System.out.println("读取结果:" + rs);
System.out.println("--------------------------");
int len2 = is.read(buffer);
System.out.println("第二个桶读取了 " + len2 + " 个字节");
String rs2 = new String(buffer);
System.out.println("读取结果:" + rs2);
System.out.println("--------------------------");
}
}
第一个桶读取了 3 个字节
读取结果:abc
--------------------------
第二个桶读取了 3 个字节
读取结果:123
--------------------------
Process finished with exit code 0
-
注意:假如我在后面加两个英文字母,第三桶水读取的时候就会出现问题了!!
-
解决方法:那就是读取多少就倒出多少
package com.app.d5_byte_stream;
import java.io.FileInputStream;
import java.io.InputStream;
/**
目标:学会字节流的使用二:文件字节输入流
每次读取一桶水
*/
public class FileInputStreamDemo02 {
public static void main(String[] args) throws Exception {
// 1、创建一个文件字节输入流管道与源文件接通
InputStream is = new FileInputStream("day10-file-io-app/src/data02.txt");
// 2、创建一个byte类型的数组,作为桶,一次读取3滴水
/*byte[] buffer = new byte[3];
int len = is.read(buffer);
System.out.println("第一个桶读取了 " + len + " 个字节");
// 解码
String rs = new String(buffer);
System.out.println("读取结果:" + rs);
System.out.println("--------------------------");
int len2 = is.read(buffer);
System.out.println("第二个桶读取了 " + len2 + " 个字节");
String rs2 = new String(buffer);
System.out.println("读取结果:" + rs2);
System.out.println("--------------------------");
int len3 = is.read(buffer);
System.out.println("第三个桶读取了 " + len3 + " 个字节");
// String rs3 = new String(buffer);
// 读取多少就倒出多少
String rs3 = new String(buffer, 0, len3);
System.out.println("读取结果:" + rs3);
System.out.println("--------------------------");
int len4 = is.read(buffer);
System.out.println("第四个桶读取了 " + len4 + " 个字节"); // 已经没有内容可以读取了,返回-1*/
// 3、循环改进
byte[] buffer = new byte[3];
int len; // 记录每次读取的字节数
while ( (len = is.read(buffer)) != -1 ) {
// 读取多少倒出多少
System.out.print(new String(buffer, 0, len));
}
}
}
abc123cd
Process finished with exit code 0
-
先加上几个中文,这样看来是没问题的,也不会引起中文乱码
-
注意:假如我在
“我” 的前面加上1个英文或者数字
,就会引起中文乱码了!! -
可以看到,第一桶读取了abc,第二桶读取了123,第三桶读取了4,然后就懵逼了,因为一个桶是读取3滴水,这才1滴水,所以就出现了中文乱码的情况
-
结论:每次读取一个字节数组依旧解决不了中文乱码的问题!!!
总结
1、文件字节输入流,每次读取一个字节数组的API是哪个?
public int read(byte[] buffer){
...
}
2、每次读取一个字节数组存在什么问题?
- 读取的性能得到了提升
- 读取中文输出无法避免乱码问题
(7)一次读完全部字节
1、如何使用字节输入流读取中文内容输出不出现乱码呢?
- 定义一个与文件一样大的字节数组,一次性读取完文件的全部字节。
2、直接把文件数据全部读取到一个字节数组可以避免乱码,是否存在问题?
- 如果文件过大,字节数组可能引起内存溢出。
方式一
- 自己定义一个字节数组与文件的大小一样大,然后使用读取字节数组的方法,一次性读取完成。
方法名称 | 说明 |
---|---|
public int read(byte[] buffer) | 每次读取一个字节数组返回,如果字节已经没有可读的返回 -1 |
方式二
- 官方为字节输入流InputStream提供了如下API可以直接把文件的全部数据读取到一个字节数组中
方法名称 | 说明 |
---|---|
public byte[] readAllBytes() throws IOException | 直接将当前字节输入流对应的文件对象的字节数据装到一个字节数组返回 |
总结
1、如何使用字节输入流读取中文内容输出不乱码呢?
- 一次性读取完全部字节。
- 可以定义与文件一样大的字节数组读取,也可以使用官方API。
2、直接把文件数据全部读取到一个字节数组可以避免乱码,是否存在问题?
- 如果文件过大,定义的字节数组可能引起内存溢出。
2、文件字节输出流
- FileOutputStream类:实现类
(1)作用
- 以内存为基准,把内存中的数据以字节形式写出到磁盘文件中去的流
(2)构造器
构造器 | 说明 |
---|---|
public FileOutputStream(File file) | 创建字节输出流管道与目标文件对象接通 |
public FileOutputStream(File file, boolean append) | 创建字节输出流管道与目标文件对象接通,可追加数据 |
public FileOutputStream(String filepath) | 创建字节输出流管道与目标文件路径接通 |
public FileOutputStream(String filepath, boolean append) | 创建字节输出流管道与目标文件路径接通,可追加数据 |
(3)方法
方法名称 | 说明 |
---|---|
public void write(int a) | 写一个字节出去 |
public void write(byte[] buffer) | 写一个字节数组出去 |
public void write(byte[] buffer, int pos, int len) | 写一个字节数组的一部分出去 |
(4)流的关闭与刷新
方法名称 | 说明 |
---|---|
flush() | 刷新流,还可以继续写数据 |
close() | 关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据。 |
package com.app.d5_byte_stream;
import java.io.FileOutputStream;
import java.io.OutputStream;
/**
目标:学会使用文件字节输出流来写数据出去
*/
public class FileOutputStreamDemo04 {
public static void main(String[] args) throws Exception {
// 1、创建一个文字字节输出流管道与目标文件接通(先不要创建文件,因为你创建管道之后,会自动创建)
// 先清空之前的数据,写新数据进去
// OutputStream os = new FileOutputStream("day10-file-io-app/src/out03.txt");
// 在原有的数据上追加新数据
OutputStream os = new FileOutputStream("day10-file-io-app/src/out03.txt", true);
// 2、写数据出去
// a、public void write(int a): 写一个字节出去
os.write('a');
os.write(98);
// os.write('国'); // 注意:一个中文字占3个字节,因此,“国” 会出现中文乱码
os.write("\r\n".getBytes()); // 换行
// b、public void write(byte[] buffer): 写一个字节数组出去
byte[] buffer = {'d', 101, 102, 103};
os.write(buffer);
os.write("\r\n".getBytes()); // 换行
byte[] buffer2 = "我爱中国!abc.123/*#@;".getBytes();
os.write(buffer2);
os.write("\r\n".getBytes()); // 换行
// c、public void write(byte[] buffer, int pos, int len): 写一个字节数组的一部分出去
byte[] buffer3 = {'a',97,97, 'b'};
os.write(buffer3, 0, 3); // 写一部分字节数据
os.write("\r\n".getBytes()); // 换行
// 注意:
// os.flush(); // 写数据必须刷新数据——>可以继续使用流
os.close(); // 写完数据必须关闭流——>释放资源,包含了刷新流!关闭后不可以继续使用流了
}
}
(5)总结
1、字节输出流写数据的方法有哪些?
方法名称 | 说明 |
---|---|
public void write(int a) | 写一个字节出去 |
public void write(byte[] buffer) | 写一个字节数组出去 |
public void write(byte[] buffer, int pos, int len) | 写一个字节数组的一部分出去 |
2、字节输出流如何实现数据追加?
构造器 | 说明 |
---|---|
public FileOutputStream(String filepath, boolean append) | 创建字节输出流管道与源文件路径接通,可追加数据 |
3、字节输出流如何实现写出去的数据能换行?
os.write("\r\n".getBytes());
4、如何让写出去的数据能成功生效?
os.flush(); // 写完数据必须刷新流——>可以继续使用流
os.close(); // 写完数据必须关闭流——>包含了刷新流,关闭后不能继续使用流
3、文件拷贝
(1)案例-文件拷贝
- 需求:
- 把某个视频复制到其他目录下的 “new.wmv”
- 分析:
- 1、根据数据源创建字节输入流对象
- 2、根据目的地创建字节输出流对象
- 3、读写数据,复制视频
- 4、释放资源
package com.app.d5_byte_stream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
/**
目标:学会使用文件字节流完成文件拷贝的操作
可以拷贝一切文件:视频、图片、文件
需求:
把某个视频拷贝到其他目录下的 "new.wmv"
*/
public class CopyTest05 {
public static void main(String[] args) {
try {
// 1、创建一个文件字节输入流管道与原视频接通
InputStream is = new FileInputStream("E:/Python学习资源/Python视频类资料/爬虫入门视频/2-requests模块/7-代理IP.wmv");
// 2、创建一个文件字节输出流管道与目标文件接通
OutputStream os = new FileOutputStream("E:/JavaDevelop/文件拷贝案例测试/new.wmv");
// 3、读写数据,拷贝视频
// 定义一个字节数组存储原视频数据
byte[] buffer = new byte[1024]; // 1KB
int len; // 记录每次读取的字节数。(为了防止数据会多倒出)
// 定义一个循环,开始将原视频数据拷贝到目标路径下
while ( (len = is.read(buffer)) != -1 ) {
os.write(buffer, 0, len); // 读取多少倒出多少(保证数据的完整性)
}
System.out.println("拷贝完成~~");
// 4、关闭流
os.close();
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
拷贝完成~~
Process finished with exit code 0
总结
1、字节流适合做一切文件数据的拷贝吗?
- 适合做一切文件数据的拷贝;不适合做读取中文字输出。
- 因为任何文件的底层都是字节,拷贝是一字不漏的转移字节,只要前后文件格式、编码一致没有任何问题。