IO流
怎么学IO流?
- 先搞清楚I0流的分类、体系,
- 再挨个学习每个I0流的作用、用法。
IO流概述
I指Input,称为输入流:负责把数据读到内存中去
O指Output,称为输出流:负责写数据出去
IO流的分类
流的四大类:
- 字节输入流InputStream(读字节数据的):以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中去的流
- 字节输出流 OutoutStream(写字节数据出去的)
:以内存为基准,把内存中的数据以字节写出到磁盘文件或者网络中去的流。 - 字符输入流Reader(读字符数据的):以内存为基准,来自磁盘文件/网络中的数据以字符的形式读入到内存中去的流。
- 字符输出流Writer(写字符数据出去的):以内存为基准,把内存中的数据以字符写出到磁盘文件或者网络介质中去的流。
字节流
文件字节输入流FileInputStream
:读取字节
- 作用:以内存为基准,可以把磁盘文件中的数据以字节的形式读入到内存中去。
- 使用FileInputStream每次读取一个字节,读取性能较差,并且读取汉字输出会乱码
构造器:
FileInputStream(File file):创建字节输入流管道与源文件对象接通
FileInputStream(String pathname):创建字节输入流管道与源文件路径接通
读取文件字节数据的方法:
int read():每次读取一个字节返回,如果字节已经没有可读的返回-1、
int read(byte[] buffer):每次读取一个字节数组返回,如果字节已经没有可读的返回-1
- 目标:掌握使用文件字节输入流每次读取一个字节
- 需求:在当前模块下,创建一个a.txt文件,文件中有内容:java学科真牛批
- 请使用文件字节输入流读取文件数据,打印到控制台
//1.创建文件字节输入流对象,可以提供File对象来定位文件
//File file = new File("day09\\a.txt");
//FileInputStream fis = new FileInputStream(file);
//也可以直接提供文件路径去定位
FileInputStream fis = new FileInputStream("day09\\\\a.txt");
//2.调用read()方法,读取单个字节
int byteData = fis.read();
//System.out.println(byteData);
System.out.println((char) byteData);
//3.一个文件不可能只有一个字节,通常需要循环读取,当调用read()方法返回不是-1的时候就继续读
while ((byteData = fis.read()) != -1) {
System.out.println((char)byteData);
}
//注意:文件字节输入流可以读取数据,但是一旦涉及解码操作,就容易乱码!
- 目标:掌握使用文件字节输入流每次读取一个字节数组
需求:使用文件字节输入流一次读取一个字节数组,读取a.txt文件中的数据
//1.创建FileInputStream对象
FileInputStream fis = new FileInputStream("day09\\\\a.txt");
//2.提供一个字节数组,用来存放读取到的字节数据
byte[] bys = new byte[5];
//3.循环读取,使用一次读取一个字节数组的方法,返回值是读取到的字节个数,如果返回值是-1就说明读完了
int len;
while ((len = fis.read(bys)) != -1) {
//4.条件成立,就说明读了len个字节数据,放到了数组bys中。对字节数组进行解码,从0号索引解码len个
String str = new String(bys, 0, len);
System.out.print(str);
}
System.out.println();
- 目标:掌握使用文件字节输入流一次读完全部字节
方式1:自己定义一个字节数组与文件的大小一样大,然后使用读取字节数组的方法,一次性读取完成
方式2:官方为字节输入流InputStream提供了如下API可以直接把文件的全部数据读取到一个字节数组中 byte[] readAllBytes()
:直接将当前字节输入流对应的文件对象的字节数据装到一个字节数组返回
//1.定义一个和文件一样大的字节数组
File file = new File("day09\\a.txt");
long length = file.length();
byte[] bys = new byte[(int) length];
//2.创建文件字节输入流对象
FileInputStream fis = new FileInputStream("day09\\a.txt");
System.out.println("读取前的字节数组:" + Arrays.toString(bys));
//3.读取一次
fis.read(bys);
System.out.println("读取后的字节数组:" + Arrays.toString(bys));
//4.对整个字节数组进行解码
String str = new String(bys);
System.out.println(str);
//5.更简单的方案
byte[] bys = fis.readAllBytes();
System.out.println("读取后的字节数组:" + Arrays.toString(bys));
两种方案都不推荐,如果文件太大,会导致数组过大,可能会堆内存溢出!
文件字节输出流FileOutputStream
:写出字节
作用:以内存为基准,把内存中的数据以字节的形式写出到文件中去
- 目标:掌握使用FileOutputStream写字节数据到文件
构造器:
FileOutputStream(File file):创建字节输出流管道与源文件对象接通
FileOutputStream(File file,boolean append):创建字节输出流管道与源文件对象接通,可追加数据
FileOutputStream(String filepath):创建字节输出流管道与源文件路径接通
FileOutputStream(String filepath,boolean append):创建字节输出流管道与源文件路径接通,可追加数据
写数据的api:
write(int a):写一个字节出去
write(byte[] buffer):写一个字节数组出去
write(byte[] buffer , int pos , int len):写一个字节数组的一部分出去
需求:往b.txt文件,写出内容:“abc”
//1.创建FileOutputStream对象,定位文件
//FileOutputStream fos = new FileOutputStream(new File("day09\\b.txt"));
FileOutputStream fos = new FileOutputStream("day09\\b.txt");
//2.如果不想覆盖原文件内容,构造器第二个参数给true
//FileOutputStream fos = new FileOutputStream("day09\\b.txt", true);
//3.写出a
//fos.write(97);
//fos.write(98);
//fos.write(99);
byte[] bys = {97, 98, 99};
//4.可以一次写出一个字节数组
fos.write(bys);
//5.也可以一次写出一个字节数组的一部分
fos.write(bys, 1, 2);
//6.如果换行,写出"\r\n"
byte[] newLineBys = "\r\n".getBytes();
fos.write(newLineBys);
//7.写出一个字符串
byte[] msgBys = "换行后的内容".getBytes();
fos.write(msgBys);
//8.养成好习惯,流不用了记得关闭
fos.close();
FileWriter(文件字符输出流)
文件字符输入流-读字符数据进来
- 目标:掌握使用FileReader一次读取一个字符
构造器:
FileReader(File file):创建字符输入流管道与源文件对象接通
FileReader(String pathname):创建字符输入流管道与源文件路径接通
读取字符的方法:int read():每次读取一个字符返回,如果字符已经没有可读的返回-1
需求:从a.txt文件中,使用文件字符输入流读取数据!一次读取一个字符
//1.创建FileReader对象,定位要读取的文件
//FileReader fr = new FileReader(new File("day09\\a.txt"));
FileReader fr = new FileReader("day09\\a.txt");
//2.开始读取,循环读取,一次读取一个符号,如果返回是-1就不读了
int charData;
while ((charData = fr.read()) != -1) {
System.out.print((char) charData);
}
System.out.println();
- 目标:掌握使用FileReader一次读取一个字符数组
int read(char[] buffer):每次读取一个字符数组,返回读取的字符个数,如果字符已经没有可读的返回-1
需求:在当前模块下创建文件c.txt,文件中有内容《静夜思》,使用文件字符输入流一次读取一个字符数组读取文件内容
//1.创建FileReader文件字符输入流对象,定位要读取的文件
FileReader fr = new FileReader("day09\\c.txt");
//2.定义字符数组,用来存储每一次读取到的字符数据
char[] chs = new char[5];
//3.开始循环读取,一次读取一个字符数组,返回的是读取到的字符个数,如果返回值是-1说明读完了
int len;
while ((len = fr.read(chs)) != -1) {
//4.进入循环,说明读取了len个字符放到了chs字符数组中
String str = new String(chs, 0, len);
System.out.print(str);
}
System.out.println();
}
- 目标:掌握FileWriter将内存中数据以字符形式写到磁盘文件
字符流和字节流不一样,写出数据后需要刷新,才会将数据真的写出到文件
构造器:
FileWriter(File file):创建字符输出流管道与源文件对象接通
FileWriter(File file,boolean append):创建字符输出流管道与源文件对象接通,可追加数据
FileWriter(String filepath):创建字符输出流管道与源文件路径接通
FileWriter(String filepath,boolean append):创建字符输出流管道与源文件路径接通,可追加数据
写出数据的api:
* write(int c):写一个字符
* write(char[] cbuf):写入一个字符数组
* write(char[] cbuf, int off, int len):写入字符数组的一部分
* write(String str):写一个字符串
* write(String str, int off, int len):写一个字符串的一部分
*
* 流关闭和刷新:
* flush():刷新流,还可以继续写数据
* close():关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据
*
* 注意:写出字符串"\r\n"也可以换行
//1.创建文件字符输出流对象,定位文件d.txt
FileWriter fw = new FileWriter("day09\\d.txt");
//如果希望原文件内容不被清空,第二个参数给true
//FileWriter fw = new FileWriter("day09\\d.txt", true);
//2.写出字符
fw.write(97);
//3.注意:字符流和字节流不一样,写出数据后需要刷新,才会将数据真的写出到文件
//fw.flush();
//刷新后,可以继续写出数据
//4.写出字符
fw.write('b');
//5.写出字符数组
char[] chs = {'黑', '马', '程', '序', '员'};
fw.write(chs);
//6.写出字符数组的一部分
fw.write(chs, 2, 3);
//7.可以写出一个字符串
fw.write("传智播客");
//8.也可以写出字符串的一部分
fw.write("传智播客", 0, 2);
//9.写出换行,就是写出"\r\n"
fw.write("\r\n");
fw.write("换行后的内容");
//注意:刷新可以多次,但没有必要,一般写完最后再刷新一次就行
fw.flush();
//注意:流不用了,记得关闭,关闭流也隐藏了一个刷新
fw.close();
文件字符输出流-写字符数据出去(同理)
缓冲流
字节缓冲流的作用: 提高字节流读写数据的性能
字节缓冲输入流: BufferedInputStream
字节缓冲输出流:BufferedOutputStream
字符缓冲输入流:BufferedReader
字符缓冲输出流:BufferedWriter
字节缓冲流
目标:掌握字节缓冲输入流读取数据
BufferedInputStream(InputStream is):
可以把低级的字节输入流包装成一个高级的缓冲字节输入流管道,从而提高字节输入流读数据的性能
public static void main(String[] args) throws Exception {
/**
* BufferedInputStream(InputStream is):
* 可以把低级的字节输入流包装成一个高级的缓冲字节输入流管道,从而提高字节输入流读数据的性能
*/
//1.创建缓冲字节输入流对象,提供基础的字节输入流对象
FileInputStream fis = new FileInputStream("day09\\a.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
//2.读取功能和基础字节输入流没有任何区别,一样的使用
//int byteData = bis.read();
byte[] byteArr = new byte[5];
//int len = bis.read(bys);
//3.循环读取
int len;
//实际上一次读取了8192个字节(不足这个数量以实际数量为准)到内存中的缓冲数组中,然后从内存中的缓冲数组拿了5个,放到了byteArr中
while ((len = bis.read(byteArr)) != -1) {
String str = new String(byteArr, 0, len);
System.out.println(str);
}
}
字符缓冲流
BufferedReader(字符缓冲输入流)
作用:自带8K(8192)的字符缓冲池,可以提高字符输入流读取字符数据的性能。
BufferedReader(Reader r):可以把低级的字符输入流包装成一个高级的缓冲字符输入流管道,从而提高字符输入流读数据的性能