一、字节缓冲流
1.缓冲流
就是在普通流上面添加一个大小为8192的数组缓冲区,用来提高效率
2.字节缓冲流的构造方法
(1)BufferedInputStream(InputStream in) 创建一个 BufferedInputStream并保存其参数,输入流 in供以后使用。
(2)BufferedInputStream(InputStream in, int size) 创建具有指定缓冲区大小的 BufferedInputStream ,并保存其参数,输入流 in供以后使用。
问题1:为什么在构造方法里面传入的InputStream,而不是File对象?
因为缓冲流仅仅是提供了一个数组缓冲区,真正干活的还是传入的InputStream
问题2:第二个构造方法的参数size是什么意思?
size就是缓冲流提供的数组的长度
问题3:为什么我们不需要关闭InputStream这个流?而仅仅关闭了缓冲流
因为BufferedInputStream缓冲流是对InputStream字节流进行了一层包装,这个时候它们就成了一个整体,当我们把外面的缓冲流关闭的时候,里面的字节流也会跟着被关闭
3.字节缓冲流复制文件的代码
public class Demo6 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("C:\\Users\\chun\\Desktop\\1.jpg") ;
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("day08/mn.jpg"));
int len;
byte[] bytes = new byte[1024];
while ((len=bis.read(bytes))!=-1){
bos.write(bytes,0,len);
}
bos.close();
bis.close();
}
}
//字节流总结
1.字节输入流
*抽象根类:InputStream
具体子类:FileInputStream
*读数据的方法
(1)int read() 从该输入流读取一个字节的数据
(2)int read(byte[] b) 从该输入流读取最多 b.length个字节的数据到一个字节数组。
(3)int read(byte[] b, int off, int len) 从该输入流读取最多 len个字节的数据到字节数组。
2.字节输出流
*抽象根类:OutputStream
具体子类:FileOutputStream
*写数据的方法
(1)void write(int b) 将指定的字节写入此文件输出流。
(2)void write(byte[] b) 将 b.length字节从指定的字节数组写入此文件输出流。
(3)void write(byte[] b, int off, int len) 将 len字节从指定的字节数组开始,从偏移量 off开始写入此文件输出流。
3.字节缓冲流
*字节缓冲输入流
BufferedInputStream
*字节缓冲输出流
BufferedOutputStream
//方法就是字节流的方法
4.复制文件的方式
(1)一次复制一个字节
(2)一次复制一个字节数组
(3)字节缓冲流一次复制一个字节
(4)字节缓冲流一次复制一个字节数组
字符流
一、字符流的概述
1.为什么会出现字符流? //“中文”
当我们使用字节流去读文件内容的时候,如果文件的内容都是英文时,不会出问题。
但是,如果文件中有中文时,那么就可能出现读到一半的汉字或者三分之一的汉字
当编码表是GBK的时候,那么我们读到的就是一半的汉字
当编码表是UTF-8的时候,那么这个时候读到的就是三分之一的汉字
2.什么时候会出现乱码?
第一个:复制带中文的文件 //不会,因为复制仅仅是把文件换了一个位置,里面的内容不会改变,我们也不会去读它
第二个:读带中文的文件 //会
二、编码表
1.ASCII码表:所有的码表都兼容ASCII表
a ---- 97
A ---- 65
0 ---- 48
2.GBK:在GBK中每个中文占用两个字节
GBK是我们windows系统的默认编码
3.UTF-8:在UTF-8中每个中文占用三个字节
UTF-8使我们以后开发中要使用的编码
三、字符串中的编码和解码问题
1.编码
*从现象上看:就是把能看懂的转成看不懂的
*从本质上看:就是把字符串转成字节数组
*编码的方法:
//String ---------- > byte[]
(1)byte[] getBytes() 使用平台的默认字符(idea开发工具的编码)集将该 String编码为一系列字节,将结果存储到新的字节数组中。
(2)byte[] getBytes(String charsetName) 使用命名的字符集将该 String编码为一系列字节,将结果存储到新的字节数组中。
代码实现:
byte[] bytes1 = "王小二".getBytes();
byte[] bytes2 = "王小二".getBytes("UTF-8");
System.out.println(Arrays.toString(bytes1));
System.out.println(Arrays.toString(bytes2));
2.解码
*从现象上看:就是把看不懂的转成能看懂的
*从本质上看:就是把字节数组转成字符串
*解码的方法:
//byte[] ---------- > String
(1)String(byte[] bytes) 通过使用平台的默认字符集(idea开发工具的编码)解码指定的字节数组来构造新的 String 。
(2)String(byte[] bytes, Charset charset) 构造一个新的String由指定用指定的字节的数组解码charset 。
代码实现:
System.out.println(new String(bytes1,"GBK"));
3.乱码是怎么产生的?
编码和解码使用的字符集不一致
四、转换流
1.为什么会出现这个转换流?
就是为了解决中文的读和写的乱码问题
//在IO流中,以Stream结尾的肯定是字节流,以er结尾的肯定是字符流
2.相关的类
1.InputStreamReader
字符输入流
2.OutputStreamWriter
字符输出流
3.构造方法
//字符输入流
(1)InputStreamReader(InputStream in) 创建一个使用默认字符集的InputStreamReader。
(2)InputStreamReader(InputStream in, String charsetName) 创建一个使用命名字符集的InputStreamReader。
//字符流 = 字节流 + 编码表
//字符输出流
(1)OutputStreamWriter(OutputStream out) 创建一个使用默认字符编码的OutputStreamWriter
(2)OutputStreamWriter(OutputStream out, String charsetName) 创建一个使用命名字符集的OutputStreamWriter
4.字符流写数据的物种方式
(1)void write(int c) 写一个字符
(2)void write(char[] cbuf) 写入一个字符数组
(3)void write(char[] cbuf, int off, int len) 写入字符数组的一部分
(4)void write(String str) 写一个字符串 //特别好用
(5)void write(String str, int off, int len) 写一个字符串的一部分
//面试题:close()方法和flush()方法的区别?
flush:是将数据从内存的缓冲区刷新到本地文件
close:首先将数据从内存缓冲区刷新到本地文件,接下来还会将资源释放掉
5.字符流读数据的两种方式
(1)int read() 一次读一个字符数据
//返回值 就是读取到的文件的内容
(2)int read(char[] cbuf) 一次读一个字符数组数据
//返回值是读取到的文件内容的大小, 真正的数据存放在char[]中
代码实现:
public class Demo3 {
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("day09/a.txt"));
char[] chars = new char[1024];
int len;
while ((len = isr.read(chars))!=-1){
System.out.println(new String(chars, 0, len));
}
isr.close();
}
}
6.使用字符流复制文件的案例
public class Demo2 {
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("day09/a.txt"));
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day09/b.txt"));
char[] chars = new char[1024];
int len;
while ((len = isr.read(chars))!=-1){
osw.write(chars,0,len);
osw.flush();
}
osw.close();
isr.close();
}
}
7.字符流复制文件改进版
(1)字符输入流
*FileReader
构造方法:FileReader(String fileName) 创建一个新的 FileReader ,给定要读取的文件的名称。
举例:
FileWriter fw = new FileWriter("day09/b.txt"); //执行这行代码,如果b.txt存在就会被清空,如果不存在,则创建该文件
(2)字符输出流
*FileWriter
构造方法:FileWriter(String fileName) 构造一个给定文件名的FileWriter对象。
(3)代码实现
public class Demo4 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("day09/a.txt");
FileWriter fw = new FileWriter("day09/b.txt");
int len;
char[] chars = new char[1024];
while ((len = fr.read(chars))!=-1){
fw.write(chars,0,len);
fw.flush();
}
fw.close();
fr.close();
}
}
(4)InputStreamReader和FileReader有什么区别?
InputStreamReader:是可以指定编码的,想写什么编码都可以 //一般用在源码中
FileReader:它只能使用平台默认的编码 //开发中常用
8.字符缓冲流
(1)对比着字节缓冲流去学
*字节缓冲流
BufferedInputStream
BufferedOutputStream
*字符缓冲流
BufferedReader
BufferedWriter
(2)构造方法
*BufferedReader(Reader in) 创建使用默认大小的输入缓冲区的缓冲字符输入流。
//BufferedReader br = new BufferedReader(new FileReader("day09/a.txt"));
*BufferedReader(Reader in, int sz) 创建使用指定大小的输入缓冲区的缓冲字符输入流。
//BufferedReader br = new BufferedReader(new FileReader("day09/a.txt"),8192);
//注意:字符缓冲流也仅仅是在字符流的基础上加了一个数组缓冲区,真正干活的还是字符流。所以字符缓冲流可以使用字符流的方法
(3)字符缓冲流复制文件案例
public class Demo5 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("day09/a.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("day09/b.txt"));
int len;
char[] chars = new char[1024];
while ((len=br.read(chars))!=-1){
bw.write(chars,0,len);
bw.flush();
}
bw.close();
br.close();
}
}
9.字符缓冲流的特有功能 //(☆☆☆☆☆)
(1)字符缓冲输入流的特有功能
String readLine()读一行文字。 结果包含行的内容的字符串,不包括任何行终止字符如果流的结尾已经到达,则为null
//返回值:String类型的,存放的是读取到的文件内容 功能:读取一行数据
//注意事项:读取的内容不包括回车换行符
(2)字符缓冲输出流特有功能
void newLine() 写一行行分隔符,行分隔符字符串由系统属性定义
// 功能:换行
//注意事项:可以根据不同操作系统换行
(3)使用字符缓冲流的特有功能来复制文件
代码实现:
public class Demo6 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("day09/a.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("day09/b.txt"));
String result = null;
while ((result=br.readLine())!=null){
bw.write(result);
bw.newLine();
bw.flush();
}
bw.close();
br.close();
}
}
//注意:
(1)下面三行代码一定要连写
bw.write(result);
bw.newLine();
bw.flush();
(2)使用字符缓冲流特有功能复制文件的时候,会产生一个问题:复制后的文件会多一个换行
//IO流的总结
一、字节流
1.字节输入流
*抽象根类:InputStream
具体子类:FileInputStream
*读数据的方法
(1)int read() 从该输入流读取一个字节的数据
(2)int read(byte[] b) 从该输入流读取最多 b.length个字节的数据到一个字节数组。
(3)int read(byte[] b, int off, int len) 从该输入流读取最多 len个字节的数据到字节数组。
2.字节输出流
*抽象根类:OutputStream
具体子类:FileOutputStream
*写数据的方法
(1)void write(int b) 将指定的字节写入此文件输出流。
(2)void write(byte[] b) 将 b.length字节从指定的字节数组写入此文件输出流。
(3)void write(byte[] b, int off, int len) 将 len字节从指定的字节数组开始,从偏移量 off开始写入此文件输出流。
3.字节缓冲流
*字节缓冲输入流
BufferedInputStream
*字节缓冲输出流
BufferedOutputStream
//方法就是字节流的方法
4.复制文件的方式
(1)一次复制一个字节
(2)一次复制一个字节数组
(3)字节缓冲流一次复制一个字节
(4)字节缓冲流一次复制一个字节数组
二、字符流
1.字符输入流
*抽象根类 Reader
具体子类:
InputStreamReader:输入转换流
FileReader:字符输入流
*读数据的方法
(1)int read() 一次读一个字符数据
(2)int read(char[] cbuf) 一次读一个字符数组数据
2.字符输出流
*抽象根类 Writer
具体子类:
OutputStreamWriter:输出转换流
FileWriter:字符输出流
*读数据的方法
(1)void write(int c) 写一个字符
(2)void write(char[] cbuf) 写入一个字符数组
(3)void write(char[] cbuf, int off, int len) 写入字符数组的一部分
(4)void write(String str) 写一个字符串 //特别好用
(5)void write(String str, int off, int len) 写一个字符串的一部分
3.字符缓冲流
(1)字符缓冲输入流:BufferedReader
*特有方法:
String readLine()读一行文字。 结果包含行的内容的字符串,不包括任何行终止字符如果流的结尾已经到达,则为null
(2)字符缓冲输出流 BuffederWriter
*特有方法:
void newLine() 写一行行分隔符,行分隔符字符串由系统属性定义
4.复制文件的方式
(1)普通字符流一次复制一个字符
(2)普通字符流一次复制一个字符数组
(3)字符缓冲流一次复制一个字符
(4)字符缓冲流一次复制一个字符数据
(5)字符缓冲流特有功能复制文件
//应用:
*什么时候使用字符流:
// "读"或者"写"一个带中文的文件
*什么时候使用字节流:
//其他情况下一律使用字节流,比如复制文件、查看非中文文件的内容。。。。