文章目录
字节缓冲区流
字节流一次读写一个数组的速度比一次读写一个字节的速度快很多,这是加入了数组这样的缓冲区效果。
- 字节缓冲输出流BufferedOutputStream
- 字节缓冲输入流BufferedInputStream
字节缓冲输出流
构造方法:BufferedOutputStream(OutputStream out)
这种构造方法提供了一个默认的缓冲区大小8192
构造方法传递的是OutputStream,而不是具体的文件或路径,因为字节缓冲区仅仅提供缓冲区,真正的底层读写数据还得基本的流对象进行操作
//创建对象
//FileOutputStream fos = new FileOutputStream("a.txt");
//BufferedOutputStream bos = new BufferedOutputStream(fos);
//等价于如下
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("a.txt"));
bos.write("hello".getBytes());
bos.close();
字节缓冲输入流
构造方法:BufferedIntputStream(IntputStream in)
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
//方式1:一次读取一个字节
int by;
while((by=bis.read())!=-1) {
System.out.print((char)by);
}
//方式2:一次读取一个字节数组
byte[] bys = new byte[1024];
int len;
while((len=bis.read(bys))!=-1) {
System.out.print(new String(bys,0,len));
}
bis.close();
字节流四种方式复制AVI并测试效率
需求:把d:\\复制图片.avi复制到当前项目目录下的copy.avi中
四种方式比较复制效率
基本字节流一次读写一个字节
基本字节流一次读写一个字节数组
缓冲字节流一次读写一个字节
缓冲字节流一次读写一个字节数组
提示:复制文件的时间计算可以采用System类的方法实现:public static long currentTimeMillis():返回以毫秒为单位的当前时间
把四种方式写成方法:
//基本字节流一次读写一个字节
private static void method1() throws IOException {
//封装数据源
FileInputStream fis = new FileInputStream("d:\\复制图片.avi");
//封装目的地
FileOutputStream fos = new FileOutputStream("copy.avi");
int by;
while((by=fis.read())!=-1) {
fos.write(by);
}
fos.close();
fis.close();
}
//基本字节流一次读写一个字节数组
private static void method2() throws IOException {
FileInputStream fis = new FileInputStream("d:\\复制图片.avi");
FileOutputStream fos = new FileOutputStream("copy.avi");
byte[] bys = new byte[1024];
int len;
while((len=fis.read(bys))!=-1) {
fos.write(bys,0,len);
}
fis.close();
fos.close();
}
//缓冲字节流一次读写一个字节
private static void method3() throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("d:\\复制图片.avi"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.avi"));
int by;
while((by=bis.read())!=-1) {
bos.write(by);
}
bos.close();
bis.close();
}
//缓冲字节流一次读写一个字节数组
private static void method4() throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("d:\\复制图片.avi"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.avi"));
byte[] bys = new byte[1024];
int len;
while((len=bis.read(bys))!=-1) {
bos.write(bys,0,len);
}
bos.close();
bis.close();
}
注释掉其余方法,分开测试,计算时间
public static void main(String[] args) throws IOException {
//记录开始时间
long start = System.currentTimeMillis();
method1(); //共耗时50233毫秒
method2(); //共耗时79毫秒
method3(); //共耗时197毫秒
method4(); //共耗时30毫秒
//记录结束时间
long end = System.currentTimeMillis();
System.out.println("共耗时:"+(end-start)+"毫秒");
}
复制效率最高的方式是:缓冲字节流一次读写一个字节数组
转换流出现的原因
字节流读数据可能出现问题:
字节流一次读取一个字节的方式读取带有文字的文件是有问题的,因为读取到一个字节后就转为字符在控制台输出了,而汉字是由2个字节组成的,所以这里会出问题
FileInputStream fis = new FileInputStream("a.txt");
int by;
while((by=fis.read())!=-1) {
System.out.print((char)by); //输出ä½ å¥½,实际文件中是你好
}
文件复制的时候,字节流读取一个字节,写入一个字节,没有出现问题,是因为最终底层会根据字节做拼接得到汉字
汉字存储的规则:左边的字节数据肯定是负数,右边的字节可能是负数,也可能是整数,大部分情况下是负数
String s = "hello";
byte[] bys = s.getBytes();
System.out.println(Arrays.toString(bys)); //[104, 101, 108, 108, 111]
String s2 = "你好";
byte[] bys2 = s2.getBytes();
System.out.println(Arrays.toString(bys2));
编码表
编码表:由字符及其对应的数据组成的一张表
常见的编码表:
- ASCII:美国标准信息交换码,用一个字节的7位表示数据
- ISO-8859-1:欧洲码表,用一个字节的8位表示数据,兼容ASCII
- GB2312:中文码表,兼容ASCII
- GBK:中文码表的升级版,融合了更多的中文文字符号,兼容ASCII
- UTF-8:是一种可变长度的字符编码,用1-3个字节表示数据,又称为万国码,兼容ASCII。用在网页上可以统一页面中的中文简体繁体和其他语言的显示。
用同一个编码表编码和解码是正常的,用不同的编码表分开编码解码会出现乱码问题。
乱码问题:针对同一个数据采用的编码和解码的编码表不一致导致的。
String类中的编码和解码问题
编码:把看得懂的变成看不懂的
public byte[] getBytes(String charsetName) throws UnsupportedEncodingException
使用指定的字符集将此String编码为byte序列,并将结果存储到一个新的byte数组中
解码:把看不懂的变成看得懂的
public String(byte[] bytes, String charsetName)
通过使用指定的charset解码指定的byte数组,构造一个新的String
String s = "你好";
byte[] bys = s.getBytes(); //使用平台的默认字符集将此String编码为byte序列
System.out.println(Arrays.toString(bys)); //[-28, -67, -96, -27, -91, -67]
byte[] bys1 = s.getBytes("GBK"); //指定编码GBK
System.out.println(Arrays.toString(bys1)); //[-60, -29, -70, -61]
byte[] bys2 = s.getBytes("UTF-8"); //指定编码GBK
System.out.println(Arrays.toString(bys2)); //[-28, -67, -96, -27, -91, -67]
String ss = new String(bys); //通过平台默认的字符集解码指定的byte数组
System.out.println(ss);
String ss1 = new String(bys1,"GBK"); //指定编码GBK
System.out.println(ss1);
String ss2 = new String(bys1,"UTF-8"); //指定编码UTF-8
System.out.println(ss2); //出现乱码
编码和解码的方式要一致
转换流
转换流其实就是一个字符流
转换流 = 字节流+编码表
转换流中的编码和解码问题
OutputStreamWriter 字符输出流
public OutputStreamWriter(OutputStream out)
根据默认编码把字节流的数据转换为字符流
public OutputStreamWriter(OutputStream out, String charsetName)
根据指定编码把字节流数据转换为字符流
InputStreamWriter 字符输入流
public InputStreamWriter(InputStream in)
用默认的编码读数据
public InputStreamWriter(InputStream in, String charsetName)
用指定的编码读取数据
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"));
osw.write("你好");
osw.close();
OutputStreamWriter osw1 = new OutputStreamWriter(new FileOutputStream("osw1.txt"),"GBK");
osw1.write("你好");
osw1.close();
OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream("osw2.txt"),"UTF-8");
osw2.write("你好");
osw2.close();
InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt"));
int ch;
while((ch=isr.read())!=-1) {
System.out.print((char)ch);
}
isr.close();
InputStreamReader isr1 = new InputStreamReader(new FileInputStream("osw1.txt"),"GBK");
int ch1;
while((ch1=isr1.read())!=-1) {
System.out.print((char)ch1);
}
isr1.close();
OutputStreamWriter写数据的5种方式
public void write(int c):写一个字符
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt"));
osw.write(97);
osw.write('a');
//写完数据后没有发现数据
//1个字符等于两个字节,文件中的数据存储的基本单位是字节
//void flush():刷新该流的缓冲
osw.flush();
osw.close(); //关闭此流,但要先刷新
public void write(char[] cbuf):写一个字符数组
char[] chs = {'a', 'b','c', 'd', 'e'};
osw.write(chs);
public void write(char[] cubf, int off, int len):写一个字符数组的一部分
char[] chs = {'a', 'b','c', 'd', 'e'};
osw.write(chs,1,3); //bcd
public void write(String str):写一个字符串
osw.write("hello");
public void write(String str, int off, int len):写一个字符串的一部分
osw.write("hello",0,3); //hel
InputStreamReader读数据的2种方式
public int read():一次读取一个字符
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));
int ch;
while((ch=isr.read())!=-1) {
System.out.print((char)ch);
}
isr.close();
public int read(char[] cbuf):一次读取一个字符数组
char[] chs = new char[1024];
int len;
while((len=isr.read(chs))!=-1) {
System.out.print(new String(chs,0,len));
}
字符流的练习
复制Java文件
需求:
把当前项目目录下的StringDemo.java内容复制到当前项目下Copy.java中
数据源:StringDemo.java – 读数据 – 字符流 – InputStreamReader
目的地:Copy.java – 写数据 – 字符流 – OutputStreamWriter
方式1:一次读写一个字符
InputStreamReader isr = new InputStreamReader(new FileInputStream("StringDemo.java"));
OutputStreamWriter osr = new OutputStreamWriter(new FileOutputStream("copy.java"));
int ch;
while((ch=isr.read())!=-1) {
osr.write(ch);
}
isr.close();
osr.close();
方式2:一次读写一个字符数组
char[] chs = new char[1024];
int len;
while((len=isr.read(chs))!=-1) {
osr.write(new String(chs,0,len));
}
复制Java文件改进版
需求:
把当前项目目录下的StringDemo.java内容复制到当前项目下Copy.java中(改进版)
转换流的名字比较长,而我们常见的操作都是按照的本地默认编码实现的,为了简化书写,转换流提供了对应的子类:
FileWriter:写入字符文件的便捷类
FileReader:读取字符文件的便捷类
OutputStreamWriter = FileOutputStream + 编码表
FileWriter = FileOutputStream + 编码表
构造方法: FileWriter(String fileName)
InputStreamReader = FileInputStream + 编码表
FileReader = FileInputStream + 编码表
构造方法: FileReader(String fileName)
数据源:StringDemo.java – 读数据 – 字符流 – FileReader
目的地:Copy.java – 写数据 – 字符流 – FileWriter
方式1:一次读写一个字符
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("StringDemo.java");
FileWriter fw = new FileWriter("copy.java");
int ch;
while((ch=fr.read())!=-1) {
fw.write(ch);
}
fw.close();
fr.close();
}
方式2:一次读写一个字符数组
char[] chs = new char[1024];
int len;
while((len=fr.read(chs))!=-1) {
fw.write(chs,0,len);
}
字符缓冲区流
字符缓冲输出流
BufferedWriter:将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。可以指定缓冲区大小,或者接受默认的大小。在大多数情况下,默认值就足够大了
构造方法:BufferedWriter(Writer out)
BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));
bw.write("hello");
bw.close();
字符缓冲输入流
BufferedReader:从字符输入流中读取文本,缓冲哥哥自负,从而实现字符、数组和行的高效读取。可以指定缓冲区大小,或者接受默认的大小。在大多数情况下,默认值就足够大了
构造方法:BufferedReader(Reader in)
BufferedReader br = new BufferedReader(new FileReader("StringDemo.java"));
int ch;
while((ch=br.read())!=-1) {
System.out.print((char)ch);
}
br.close();
char[] chs = new char[1024];
int len;
while((len=br.read(chs))!=-1) {
System.out.print(new String(chs,0,len));
}
练习 复制文本文件
需求:把项目目录下的a.txt内容复制到项目目录下的b.txt中
数据源:a.txt – 读数据 – 字符流 – InputStreamReader – FileReader – BufferedReader
目的地:b.txt – 写数据 – 字符流 – OutputStreamWriter – FileWriter – BufferedWriter
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
int ch;
while((ch=br.read())!=-1) {
bw.write(ch);
}
br.close();
bw.close();
}
char[] chs = new char[1024];
int len;
while((len=br.read(chs))!=-1) {
bw.write(new String(chs,0,len));
}
特殊功能
BufferedWriter
void newLine():写入一个行分隔符,这个行分隔符是由系统决定的
BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
for(int x=0; x<3; x++) {
bw.write("hello");
//bw.write("\r\n");
bw.newLine();
bw.flush();
}
bw.close();
BufferedReader
String readLine():读取一个文本行,包含该行内容的字符串,不包含任何终止符,如果已到达流末尾,则返回null
BufferedReader br = new BufferedReader(new FileReader("bw.txt"));
String line = br.readLine();
System.out.println(line); //hello1
line = br.readLine();
System.out.println(line); //hello2
line = br.readLine();
System.out.println(line); //hello3
line = br.readLine();
System.out.println(line); //null
//循环改进
String line1;
while((line1=br.readLine())!=null) {
System.out.print(line1); //hello1hello2hello3
}
br.close();
特殊功能复制Java文件
数据源:StringDemo.java – BufferedReader
目的地:copy.java – BufferedWriter
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("StringDemo.java"));
BufferedWriter bw = new BufferedWriter(new FileWriter("copy.java"));
String line;
while((line=br.readLine())!=null) {
bw.write(line);
bw.newLine();
bw.flush();
}
br.close();
bw.close();
}
字符流练习
5种方式复制文本文件
数据源:d:\\林青霞.txt
目的地:窗里窗外.txt
5种方式
- 基本字符流一次读写一个字符
- 基本字符流一次读写一个字符数组
- 缓冲字符流一次读写一个字符
- 缓冲字符流一次读写一个字符数组
- 缓冲字符流一次读写一个字符串
public static void main(String[] args) throws IOException {
method1();
method2();
method3();
method4();
method5();
}
public static void method1() throws IOException {
FileReader fr = new FileReader("d:\\林青霞.txt");
FileWriter fw = new FileWriter("窗里窗外.txt");
int ch;
while((ch=fr.read())!=-1) {
fw.write(ch);
}
fr.close();
fw.close();
}
public static void method2() throws IOException {
FileReader fr = new FileReader("d:\\林青霞.txt");
FileWriter fw = new FileWriter("窗里窗外.txt");
char[] chs = new char[1024];
int len;
while((len=fr.read(chs))!=-1) {
fw.write(chs,0,len);
}
fr.close();
fw.close();
}
public static void method3() throws IOException {
BufferedReader br = new BufferedReader(new FileReader("d:\\林青霞.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("窗里窗外.txt"));
int ch;
while((ch=br.read())!=-1) {
bw.write(ch);
}
br.close();
bw.close();
}
public static void method4() throws IOException {
BufferedReader br = new BufferedReader(new FileReader("d:\\林青霞.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("窗里窗外.txt"));
char[] chs = new char[1024];
int len;
while((len=br.read(chs))!=-1) {
bw.write(chs,0,len);
}
br.close();
bw.close();
}
public static void method5() throws IOException {
BufferedReader br = new BufferedReader(new FileReader("d:\\林青霞.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("窗里窗外.txt"));
String line;
while((line=br.readLine())!=null) {
bw.write(line);
bw.newLine();
bw.flush();
}
br.close();
bw.close();
}
把集合中的字符串数据存储到文本文件
需求:把ArrayList集合中的字符串数据存储到文本文件,每一个字符串元素作文文件中的一行数据
分析:
- 创建集合对象
- 往集合中添加字符串元素
- 创建字符缓冲输出流对象
- 遍历集合得到每一个字符串元素,把字符串元素作为数据写入到文本文件
- 释放资源
ArrayList<String> array = new ArrayList<>();
array.add("hello");
array.add("world");
array.add("java");
BufferedWriter bw = new BufferedWriter(new FileWriter("array.txt"));
for(String s:array) {
bw.write(s);
bw.newLine();
bw.flush();
}
bw.close();
把文本文件中的字符串数据读取到集合
需求:从文本文件中读取数据到ArrayList集合中,并遍历集合。每一行数据作为一个字符串元素
分析:
- 创建字符缓冲输入流对象
- 创建集合对象
- 读取数据,每一次读取一行并把该数据作为元素存储到集合中
- 释放资源
- 遍历集合
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("array.txt"));
ArrayList<String> array = new ArrayList<>();
String line;
while((line=br.readLine())!=null) {
array.add(line);
}
br.close();
for(String s: array) {
System.out.println(s);
}
}
集合中的学生对象数据存储到文本文件
需求:把ArrayList集合中的学生数据存储到文本文件,每一个学生数据作为文件中的一行数据
定义一个学生类:学号,姓名,年龄,所在地
public class Student {
private String sid;
private String name;
private int age;
private String city;
public Student() {}
public Student(String sid, String name, int age, String city) {
this.sid = sid;
this.name = name;
this.age = age;
this.city = city;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public String toString() {
return "Student{" +
"sid='" + sid + '\'' +
", name='" + name + '\'' +
", age=" + age +
", city='" + city + '\'' +
'}';
}
}
分析:
- 创建集合对象
- 创建学生对象
- 把学生对象添加到集合中
- 创建字符缓冲输出流对象
- 遍历集合,得到每一个学生对象,然后把该对象的数据拼接成一个制定合适的字符串写到文本文件
- 释放资源
public static void main(String[] args) throws IOException {
ArrayList<Student> array = new ArrayList<>();
Student s1 = new Student("it001","林青霞",30,"西安");
Student s2 = new Student("it002","张曼玉",35,"北京");
Student s3 = new Student("it003","王祖贤",33,"上海");
array.add(s1);
array.add(s2);
array.add(s3);
BufferedWriter bw = new BufferedWriter(new FileWriter("student.txt"));
for(Student s: array) {
bw.write(s.getSid()+","+s.getName()+","+s.getAge()+","+s.getCity());
bw.newLine();
bw.flush();
}
bw.close();
}
把文本文件中的学生对象数据读取到集合
需求:从文本文件中读取学生数据到ArrayList集合中,并遍历集合。每一行数据作为一个学生元素
提示:这里要使用String中的一个方法:split()
分析:
- 创建字符缓冲输入流对象
- 创建集合对象
- 读取数据,每一次读取一行数据,把该行数据想办法封装成学生对象并把学生对象存储到集合中
- 释放资源
- 遍历集合
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("Student.txt"));
ArrayList<Student> array = new ArrayList<>();
String line;
while((line=br.readLine())!=null) {
String[] strArray = line.split(",");
Student s = new Student();
s.setSid(strArray[0]);
s.setName(strArray[1]);
s.setAge(Integer.parseInt(strArray[2]));
s.setCity(strArray[3]);
array.add(s);
}
br.close();
for(Student s : array) {
System.out.println(s);
}
}