目录
b.文件字符输出流(FileWriter)写数据出去的API
b.如果代码编码和文件编码不一致,使用字符流直接读取还能不乱码吗?
b.字符输入转换流:InputStreamReader,可以把原始的字节流按照指定编码转换成字符输入流。
a.字符输入转换流:OutputStreamWriter,可以把字节输出流按照指定编码转换成字符输出流。
一、缓冲流
1、字符输入流- 一次读取一个字符
a.存在问题
字节流读取中文输出会存在什么问题?
答:会乱码。或者内存溢出。
b.
读取中文输出,哪个流更合适,为什么?
答:字符流更合适,最小单位是按照单个字符读取的。
c.文件字符输入流:Reader
作用:
以内存为基准,把磁盘文件中的数据以字符的形式读取到内存中去。
构造器:
构造器 | 说明 |
public FileReader(File file) | 创建字符输入流管道与源文件对象接通 |
public FileReader(String pathname) | 创建字符输入流管道与源文件路径接通 |
常用方法:
方法名称 | 说明 |
public int read() | 每次读取一个字符返回,如果字符已经没有可读的返回-1 |
public int read(char[] buffer) | 每次读取一个字符数组,返回读取的字符个数,如果字符已经没有可读的返回-1 |
d.字符流一次读取一个字符的优缺点
读取中文字符不会出现乱码(如果代码文件编码一致)。
性能较慢。
2、字符输入流- 一次读取一个字符数组
a.文件字符输入流:FileReader
作用:
以内存为基准,把磁盘文件中的数据以字符的形式读取到内存中去。
b.常用方法
方法名称 | 说明 |
public int read() | 每次读取一个字符返回,如果字符已经没有可读的返回-1 |
public int read(char[] buffer) | 每次读取一个字符数组,返回读取的字符数,如果字符已经没有可读的返回-1 |
c.字符流一次读取一个字符数组的优缺点
读取的性能得到了提升。
读取中文字符输出不会乱码。
3、字符输出流
a.文件字符输出流:FileWriter
作用:
以内存为基准,把内存中的数据以字符的形式写出到磁盘文件中去的流。
构造器:
构造器 | 说明 |
public FileWriter(File file) | 创建字符输出流管道与源文件对象接通 |
public FileWriter(File file,boolean append) | 创建字符输出流管道与源文件对象接通,可追加数据 |
public FileWriter(String filepath) | 创建字符输出流管道与源文件路径接通 |
public FileWriter(String filepath,boolean append) | 创建字符输出流管道与源文件路径接通,可追加数据 |
b.文件字符输出流(FileWriter)写数据出去的API
方法名称 | 说明 |
void write(int c) | 写一个字符 |
void write(char[] cbuf) | 写入一个字符数组 |
void write(char[] cbuf, int off, int len) | 写入字符数组的一部分 |
void write(String str) | 写一个字符串 |
void write(String str, int off, int len) | 写一个字符串的一部分 |
c.流的关闭与刷新
方法 | 说明 |
flush() | 刷新流,还可以继续写数据 |
close() | 关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据 |
d. 字节流、字符流的使用场景总结
字节流适合做一切文件数据的拷贝(音视频,文本)
字节流不适合读取中文内容输出
字符流适合做文本文件的操作(读,写)
二、转换流
1、缓冲流概述、字节缓冲流的使用
a.缓冲流概述
缓冲流也称为高效流、或者高级流。之前学习的字节流可以称为原始流。
作用:缓冲流自带缓冲区、可以提高原始字节流、字符流读写数据的性能
b.字节缓冲流性能优化原理
字节缓冲输入流自带了8KB缓冲池,以后我们直接从缓冲池读取数据,所以性能较好。
字节缓冲输出流自带了8KB缓冲池,数据就直接写入到缓冲池中去,写数据性能极高了
c.字节缓冲流
字节缓冲输入流:BufferedInputStream,提高字节输入流读取数据的性能。
字节缓冲输出流:BufferedOutputStream,提高字节输出流读取数据的性能。
构造器 | 说明 |
public BufferedInputStream(InputStream is) | 可以把低级的字节输入流包装成一个高级的缓冲字节输入流管道,从而提高字节输入流读数据的性能 |
public BufferedOutputStream(OutputStream os) | 可以把低级的字节输出流包装成一个高级的缓冲字节输出流,从而提高写数据的性能 |
2、字节缓冲流的性能分析
a.观察性能情况
b.需求:
分别使用低级字节流和高级字节缓冲流拷贝大视频,记录耗时
c.分析
1.使用低级的字节流按照一个一个字节的形式复制文件。
2.使用低级的字节流按照一个一个字节数组的形式复制文件。
3.使用高级的缓冲字节流按照一个一个字节的形式复制文件。
4.使用高级的缓冲字节流按照一个一个字节数组的形式复制文件。
d.代码
/**
目标:比较IO流当中的原始流和高级流的性能
*/
public class ByteBufferTimeDemo {
private static final String SRC_FILE = "C:\\Users\\ls\\Videos\\ce7dc35e4ceda89516453426094290f8.mp4";
private static final String DEST_FILE = "C:\\Users\\ls\\Videos\\";
public static void main(String[] args) {
// copy01(); //使用低级的字节流按照一个一个字节的形式复制文件
copy02(); //使用低级的字节流按照一个一个字节数组的形式复制文件
// copy03(); //使用缓流按照一个一个字节复制
copy04(); //使用缓流按照一个一个字节数组复制
}
/**
使用缓流按照一个一个字节数组复制
*/
private static void copy04() {
long startTime = System.currentTimeMillis();
try(
//1、创建一个低级的字节输入流与源文件接通
InputStream is = new FileInputStream(SRC_FILE);
//a.把原始的字节输入流包装成高级的缓冲字节输入流
InputStream bis = new BufferedInputStream(is);
//2、创建低级的字节输出流与目标文件接通
OutputStream os = new FileOutputStream(DEST_FILE + "舞蹈机器人04.mp4");
//b.把字节输出流管道包装成高级的缓冲字节输出流管道
OutputStream bos = new BufferedOutputStream(os);
) {
//3、定义一个字节数组转移数据
byte[] butter = new byte[1024];
int len; //记录每次读取字节数
while ((len = bis.read(butter)) != -1 ){
bos.write(butter,0,len);
}
} catch (Exception e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("使用缓流按照一个一个字节数组复制:"+(endTime-startTime)/1000.0+"s");
}
/**
使用缓流按照一个一个字节复制
*/
private static void copy03() {
long startTime = System.currentTimeMillis();
try(
//1、创建一个低级的字节输入流与源文件接通
InputStream is = new FileInputStream(SRC_FILE);
//a.把原始的字节输入流包装成高级的缓冲字节输入流
InputStream bis = new BufferedInputStream(is);
//2、创建低级的字节输出流与目标文件接通
OutputStream os = new FileOutputStream(DEST_FILE + "舞蹈机器人03.mp4");
//b.把字节输出流管道包装成高级的缓冲字节输出流管道
OutputStream bos = new BufferedOutputStream(os);
){
//3、定义一个变量记录每次读取得字节(一个一个字节的复制)
int b;
while ((b = bis.read()) != -1){
bos.write(b);
}
}
catch (Exception e){
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("使用缓流按照一个一个字节复制耗时:"+(endTime-startTime)/1000.0+"s");
}
/**
使用低级的字节流按照一个一个字节数组的形式复制文件
*/
private static void copy02() {
long startTime = System.currentTimeMillis();
try(
//这里面只能放置资源对象,用完会自动关闭;自动调用资源对象的close方法关闭资源(即使出现异常也会做关闭操作)
//1、创建一个字节输入流管道与原视频接通
InputStream is = new FileInputStream(SRC_FILE);
//2、创建一个字节输出流管道与目标文件接通
OutputStream os = new FileOutputStream(DEST_FILE + "舞蹈机器人02.mp4")
) {
//3、定义一个字节数组转移数据
byte[] butter = new byte[1024];
int len; //记录每次读取字节数
while ((len = is.read(butter)) != -1 ){
os.write(butter,0,len);
}
} catch (Exception e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("使用低级的字节流按照一个一个字节数组的形式复制文件耗时:"+(endTime-startTime)/1000.0+"s");
}
/**
使用低级的字节流按照一个一个字节的形式复制文件
*/
private static void copy01() {
long startTime = System.currentTimeMillis();
try(
//1、创建一个低级的字节输入流与源文件接通
InputStream is = new FileInputStream(SRC_FILE);
//2、创建低级的字节输出流与目标文件接通
OutputStream os = new FileOutputStream(DEST_FILE + "舞蹈机器人01.mp4")
){
//3、定义一个变量记录每次读取得字节(一个一个字节的复制)
int b;
while ((b = is.read()) != -1){
os.write(b);
}
}
catch (Exception e){
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("使用低级的字节流按照一个一个字节的形式复制文件耗时:"+(endTime-startTime)/1000.0+"s");
}
}
e.总结
建议使用字节缓冲输入流、字节缓冲输出流,结合字节数组的方式,目前来看是性能最优的组合。
3、字符缓冲流
a.字符缓冲输入流
字符缓冲输入流:BufferedReader。
作用:提高字符输入流读取数据的性能,除此之外多了按照行读取数据的功能。
构造器 | 说明 |
public BufferedReader(Reader r) | 可以把低级的字符输入流包装成一个高级的缓冲字符输入流管道,从而提高字符输入流读数据的性能 |
b.字符缓冲输入流新增功能
方法 | 说明 |
public String readLine() | 读取一行数据返回,如果读取没有完毕,无行可读返回null |
c.字符缓冲输出流
字符缓冲输出流:BufferedWriter。
作用:提高字符输出流写取数据的性能,除此之外多了换行功能
构造器 | 说明 |
public BufferedWriter(Writer w) | 可以把低级的字符输出流包装成一个高级的缓冲字符输出流管道,从而提高字符输出流写数据的性能 |
d.字符缓冲输出流新增功能
方法 | 说明 |
public void newLine() | 换行操作 |
e.总结
1.字符缓冲流为什么提高了操作数据的性能?
字符缓冲流自带8K缓冲区
可以提高原始字符流读写数据的性能
三、转换流
1、问题引出:不同编码读取乱码问题
a.之前我们使用字符流读取中文是否有乱码?
没有的,因为代码编码和文件编码都是UTF-8。
b.如果代码编码和文件编码不一致,使用字符流直接读取还能不乱码吗?
会乱码。
文件编码和读取的编码必须一致才不会乱码。
2、字符输入转换流
a.如果如何解决乱码
使用字符输入转换流 可以提取文件(GBK)的原始字节流,原始字节不会存在问题。
然后把字节流以指定编码转换成字符输入流,这样字符输入流中的字符就不乱码了
b.字符输入转换流:InputStreamReader,可以把原始的字节流按照指定编码转换成字符输入流。
构造器 | 说明 |
public InputStreamReader(InputStream is) | 可以把原始的字节流按照代码默认编码转换成字符输入流。几乎不用,与默认的FileReader一样。 |
public InputStreamReader(InputStream is ,String charset) | 可以把原始的字节流按照指定编码转换成字符输入流,这样字符流中的字符就不乱码了(重点) |
3、字符输出转换流
a.字符输入转换流:OutputStreamWriter,可以把字节输出流按照指定编码转换成字符输出流。
构造器 | 说明 |
public OutputStreamWriter(OutputStream os) | 可以把原始的字节输出流按照代码默认编码转换成字符输出流。几乎不用。 |
public OutputStreamWriter(OutputStream os,String charset) | 可以把原始的字节输出流按照指定编码转换成字符输出流(重点) |