Java进阶10 IO流
IO流就是数据传输。I为input的缩写,表示输入读取;O为out的缩写,表示输出写出。
一、IO流体系结构
♥巧记区分tips:以Stream结尾的是字节流;以Reader、Writer结尾的都是字符流
二、字节输出流FileOutputStream
创建对象的时候和文件建立关联
1、构造方法
方法 | 说明 |
---|---|
FileOutputStream(String name) | 输入流关联文件,文件路径以字符串形式给出 |
FileOutputStream(String name,boolean append) | 第二个参数是追加写入的开关 |
FileOutputStream(File file) | 输出流关联文件,文件路径以File对象形式给出 |
FileOutputStream(File file,boolean append) | 第二个参数是追加写入的开关 |
注意事项:关联的文件如果不存在就自动创建;若存在,会清空现有的内容,再开始写入
2、成员方法
方法 | 说明 |
---|---|
void write(int b) | 写出单个字节 |
void write(byte[] b) | 写出一个字节数组 |
void write(byte[] b,int off,int len) | 写出字节数组的一部分 |
public class FileOutputStreamDemo1 {
public static void main(String[] args) throws IOException {
//创建字节输出流对象,关联要操作的文件,追加写入
FileOutputStream fos = new FileOutputStream("day10\\A.txt",true);
//写入数据
fos.write("大家好\r\n".getBytes());
byte[] bys = {97,98,99,100,101};
//写入字节数组的一部分
fos.write(bys,0,3);
}
}
3、关流
流对象使用完毕后,记得调用close方法关流及时释放资源
3.1 关流格式(7版本以后)
//注意try()中的对象,需要实现过AutoCloseable接口
try(需要调用close方法的对象){
逻辑代码
}catch(异常类名 对象名){
异常的处理方式
}
public class FileOutputStreamDemo1 {
/*
IO流异常标准处理方式(JDK7+)
*/
public static void main(String[] args) {
try( FileOutputStream fos = new FileOutputStream("day10\\A.txt");){
fos.write("大家好\r\n".getBytes());
}catch (IOException e){
e.printStackTrace();
}
}
}
3.2 关流格式(7版本以前)
需要抛异常,且需要手动调用close关流
public class FileOutputStreamDemo2 {
//抛异常
public static void main(String[] args) throws IOException {
//创建字节输出流对象,关联要操作的文件,追加写入
FileOutputStream fos = new FileOutputStream("day10\\A.txt",true);
//写入数据
fos.write("大家好\r\n".getBytes());
//关流
fos.close();
}
}
三、字节输入流FileInputStream
创建对象的时候关联文件,文件不存在会抛异常
1、构造方法
方法 | 说明 |
---|---|
FileInputStream(String name) | 输入流关联文件,文件路径以字符串形式给出 |
FileInputStream(File file) | 输入流关联文件,文件路径以File对象形式给出 |
public String(byte[] bytes,int offset,int length) | 将字节数组转换为字符串(参数1 字节数组,参数2 起始索引,参数3 转换的个数) |
注意事项:关联的文件不存在会抛出FileNotFoundException异常,文件夹的话会拒绝访问
2、成员方法
方法 | 说明 |
---|---|
int read() | 读取一个字节并返回,如果到达文件结尾则返回-1 |
int read(byte[] b) | 将读取到字节,放到传入的数组,返回读取到的有效字节个数。如果到达文件结尾则返回-1 |
public class FileInputStreamDemo1 {
public static void main(String[] args) {
try(FileInputStream fis = new FileInputStream("day10\\A.txt");){
//提升变量i的作用域
int i;
//判断是否到达文件的末尾
while((i=fis.read())!=-1){
System.out.print((char)i);
}
}catch(IOException e){
e.printStackTrace();
}
}
}
四、字节缓冲流
字节缓冲流在源代码中内置了字节数组,可以提高读写效率
构造方法 | 说明 |
---|---|
BufferedInputStream(InputStream in) | 对传入的字节输入流进行包装 |
BufferedOutputStream(OutputStream out) | 对传入的字节输出流进行包装 |
注意:缓冲流不具备读写功能,它们只是对普通的流对象进行包装;正真和文件建立关联的,还是普通的流对象
-
字节缓冲流读写过程
-
文件拷贝效率分析
结论:推荐使用普通流+自定义数组拷贝
五、字符输入流FileReader
用于读取纯文本文件,解决中文乱码问题
1、构造方法
方法 | 说明 |
---|---|
FileReader(String fileName) | 字符输入流关联文件,路径以字符串形式给出 |
FileReader(File file) | 字符输入流关联文件,路径以File对象形式给出 |
2、成员方法
方法 | 说明 |
---|---|
public int read() | 读取单个字符 |
public int read(char[] cbuf) | 读取一个字符数组,返回读取到的有效字符个数 |
3、字符集&字符编码
3.1 字符集(多个字符的集合)
-
GB2312字符集
1981年5月1日实施的简体中文汉字编码国家标准,收录7445个图形字符,其中包括6763个简体汉字
-
BIG5字符集
台湾地区繁体中文标准字符集,共收录13053个中文字,1984年实施
-
GBK字符集
2000年3月17日发布,收录21003个汉字,包含国家标准GB13000-1中的全部中日韩汉字,和BIG5编码中的所有汉字,Windows系统默认使用的就是GBK,在系统里显示为ANSI
-
Unicode字符集
国际标准字符集,它将世界各种语言的每个字符定义一个唯一的编码,以满足跨语言、跨平台的文本信息转换
3.2 字符编码
字符编码是一种映射规则,根据这个规则可以将某个字符映射成其他形式的数据以便在计算机中存储和传输。
-
GBK的字符编码
英文字符占用1个字节
中文字符占用2个字节
-
Unicode(Unicode Transfer Format)
-
UTF-16编码规则:用2~4个字节保存
-
UTF-32编码规则:固定使用4个字节保存
-
UTF-8编码规则:用1~4个字节保存(ASCII码表中的都用1个字节存;简体中文都用3个字节存)细节:中文字节都是负数
-
⭐FileReader字符输入流读取纯文本文件时,解决中文乱码问题,就是因为其底层还是有字节数组,如果读取到负数表示的字节数,系统就知道遇到了中文,会一次性拿出三个进行解码。
4、编码和解码
4.1 编码:字符转字节
成员方法 | 说明 |
---|---|
public btye[] getBytes() | 使用平台默认字符编码方式,对字符串编码 |
public byte[] getBytes(String charsetName) | 使用指定字符编码方式,对字符串编码 |
4.2 解码:字节转字符
构造方法 | 说明 |
---|---|
public String(byte[] bytes) | 使用平台默认字符编码方式,对字符串解码 |
public String(byte[] bytes,String charsetName) | 使用指定字符编码方式,对字符串解码 |
4.3 文件加密和解密(Demo)
public class ImageTest {
/*
需求:对图片加密、解密
加密(改变原始文件中的字节,就无法打开了);
解密(将文件中的字节还原成原始字节即可);
*/
public static void main(String[] args) throws IOException {
//1、创建一个字节输入流,读取要加密的图片
FileInputStream fis = new FileInputStream("D:\\itheima\\src.png");
//2、准备集合,用于存储读取到的字节(备份)
ArrayList<Integer> list = new ArrayList<>();
//3、循环读取图片中的字节
int i;
while((i=fis.read())!=-1){
//4、将读取到的字节存入集合
list.add(i);
}
//5、关闭输入流
fis.close();
//6、创建一个字节输出流,准备写出数据,因为是加密,所以写出路径与读取路径相同
FileOutputStream fos = new FileOutputStream("D:\\itheima\\src.png");
//7、遍历集合,取出字节
for (Integer pngByte : list) {
//8、改变字节,写出数据(加密)
fos.write(pngByte^2);
}
//9、关闭输出流
fos.close();
}
}
注意:因为对某个数做两次异或操作还是等于它本身。所以上述代码运行一次异或,即加密;再运行一次,字节数变回原值,即解密。
六、字符输出流FileWriter
1、构造方法
方法 | 说明 |
---|---|
FileWirter(String fileName) | 字符输出流关联文件,路径以字符串形式给出 |
FileWriter(String fileName,boolean append) | 参数2:追加写入的开关 |
FileWriter(File file) | 字符输出流关联文件,路径以File对象形式给出 |
FileWriter(File file,boolean append) | 参数2:追加写入的开关 |
2、成员方法
方法 | 说明 |
---|---|
public void write(int c) | 写出单个字符 |
public void write(char[] cbuf) | 写出一个字符数组 |
public write(char[] cbuf,int off,int len) | 写出字符数组的一部分 |
public void write(String str) | 写出字符串 |
public void write(String str,int off,int len) | 写出字符串的一部分 |
注意:字符输出流写出数据,需要调用flush或close方法,数据才会写出。flush后可以继续写出;close后不能继续写出