day12_面向对象(缓冲流、转换流、序列化流和打印流)
一.缓冲流
1.缓冲流的作用
缓冲流也叫高效流,它是对普通流的增强,增强再性能方面
2.缓冲流的分类
字节输入流 ——> 缓冲字节输入流
InputStream ——> BufferedInputStream
字节输出流 ——> 缓冲字节输出流
OutputStream ——> BufferedOutputStream
字符输入流 ——> 缓冲字符输入流
Reader ——> BufferedReader
字符输出流 ——> 缓冲字符输出流
Writer ——> BufferedWriter
3.字节缓冲流的介绍和使用
a.字节缓冲流的构造
public BufferedInputStream(InputStream in);缓冲流创建需要普通流
public BufferedOutputStream(OutputStream out);缓冲流创建需要普通流
b.字节缓冲流的高效测试
public class BufferedStreamDemo {
public static void main(String[] args) throws IOException {
//调用
long start = System.currentTimeMillis();
copy03();
long end = System.currentTimeMillis();
System.out.println("耗时:" + (end - start) + "毫秒...");
}
//定义方法:复制文件
//使用缓冲流
//定义方法:复制文件
//使用缓冲流 耗时:169毫秒...
public static void copy03()throws IOException {
//1.缓冲字节输入流
// FileInputStream fis = new FileInputStream("1.avi");
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("1.avi"));
//2.缓冲字节输出流
// FileOutputStream fos = new FileOutputStream("copy.avi");
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.avi"));
//3.复制,采用字节数组
byte[] bs = new byte[1024 * 100];
int len = 0;
while ((len = bis.read(bs)) != -1) {
bos.write(bs, 0, len);
}
//4.释放资源
bos.close();
// fos.close();
bis.close();
// fis.close();
}
//定义方法:复制文件
//使用缓冲流 耗时:4111毫秒...
public static void copy02()throws IOException {
//1.缓冲字节输入流
// FileInputStream fis = new FileInputStream("1.avi");
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("1.avi"));
//2.缓冲字节输出流
// FileOutputStream fos = new FileOutputStream("copy.avi");
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.avi"));
//3.复制
int b = 0;
while ((b = bis.read()) != -1) {
bos.write(b);
}
//4.释放资源
bos.close();
// fos.close();
bis.close();
// fis.close();
}
//定义方法:复制文件
//使用普通流
public static void copy01() throws IOException {
//1.字节输入流
FileInputStream fis = new FileInputStream("1.avi");
//2.字节输出流
FileOutputStream fos = new FileOutputStream("copy.avi");
//3.一个一个字节慢慢来
int b = 0;
while ((b = fis.read()) != -1) {
fos.write(b);
}
//4.关闭
fos.close();
fis.close();
}
}
4.字符缓冲流的介绍和使用
a.字符缓冲流的构造
public BufferedReader(Reader r); 创建缓冲字符流需要普通字符流
public BufferedWriter(Writer w);创建缓冲字符流需要普通字符流
b.字符缓冲流的2个特有方法
BufferedReader缓冲字符输入流
public String readLine(); 一次读取一行
public class BufferedReaderDemo {
public static void main(String[] args) throws Exception {
//1.创建BufferedReader对象
BufferedReader br = new BufferedReader(new FileReader("1.txt"));
//2.读取数据
// String line = br.readLine();
// System.out.println(line);
//一次读取一行的标准循环代码
String line = "";
/**
* (line = br.readLine()) != null
* a.先读一行
* b.赋值 line = 一行的内容
* c.判断 line != null
*/
while ((line = br.readLine()) != null) {
System.out.println(line);
}
//3.释放资源
br.close();
}
}
BufferedWriter缓冲字符输出流
public void newLine(); 写一个跨平台的换行符
public class BufferedWriterDemo {
public static void main(String[] args) throws IOException {
//1.创建一个BufferedWriter对象
BufferedWriter bw = new BufferedWriter(new FileWriter("1.txt"));
//2.写数据
for (int i = 0; i < 10; i++) {
bw.write("java");
//bw.write("\r\n"); //Java是跨平台
bw.newLine();//写一个跨平台换行符
}
//3.释放资源
bw.close();
}
}
5.综合练习:文本排序
将一个文件中的内容读取,根据每一行的编号,从小到大写到另一个文本文件中
public class BufferedTestDemo {
public static void main(String[] args) throws Exception {
// 综合练习:文本排序
// 将一个文件中的内容读取,根据每一行的编号,从小到大写到另外一个文本文件中
//1.将原文本一行一行读取出来,保存到集合中
ArrayList<String> lines = new ArrayList<String>();
//读取文本
BufferedReader br = new BufferedReader(new FileReader("csb.txt"));
//循环
String line = "";
while ((line = br.readLine()) != null) {
//保存到集合
lines.add(line);
}
//释放资源
br.close();
//3.对集合中文本进行排序
Collections.sort(lines, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//口诀:升序 前 - 后
return o1.charAt(0) - o2.charAt(0);
}
});
//4.写到另外一个文本中
BufferedWriter bw = new BufferedWriter(new FileWriter("csb02.txt"));
for (String str : lines) {
bw.write(str);
//换行
bw.newLine();
}
bw.close();
}
}
二.转换流*******************
1.字符集
是一个平台所能支持的所有字符的集合(文字、符号、图形、数字)(编码表等于字符集加码值)
2.字符编码(编码和解码)
就是指每一个字符和对应码值的转换规则
编码:把字符转成对应的码值 比如:a --> 97
解码:把码值转成对应的字符 比如:97 --> a
扩展:
常见的字符集和字符编码
a.ascii字符集(美国标准信息交换代码) 包含英文字母,英文标点,阿拉伯数字(128个)
其对应的字符编码ascii编码,在ascii编码中所有的字符只占一个字节
b.GBXXXX字符集
GB2312字符集 含有大概7000多个汉字(简体常用汉字)
GBK字符集 含有大概两万多个汉字(简体和繁体汉字以及日韩汉字)
GB18030字符集 含有大概70000多个汉字(目前还没有启用)
GBXXXX字符集对应的字符编码称为GBK编码,在GBK编码中一个中文占2个字节
c.Unicode字符集
万国字符集(全球几乎所有国家的字符都在此字符集中)
Unicode字符集对应的字符编码称为UTF-8编码,UTF-16编码,UTF-32编码
在UTF-8编码中一个中文占3个字节
d.ISO-8859-1字符集
拉丁字符集(西欧国家)
ISO-8859-1字符集采用ISO-8859-1字符编码,每一个字符占一个字节(二进制都是1开头,表示负数,ascii码值中二进制都是0开头的,故不冲突)
以后我们的服务器(Tomcat7.0)默认采用就是ISO-8859-1,我们需要手动改为GBK或者UTF-8
3.编码引出的问题
总结:只要是乱码,99%的情况下都是由编码不一致引起的
比如文本是GBK,读取时,IDEA默认使用的是UTF-8,所以出现乱码
public class LuanMaDemo {
public static void main(String[] args) throws Exception {
//1.读取文件 2.txt(记事本默认是GBK编码)
FileReader fr = new FileReader("2.txt"); //IDEA中读取中时,默认UTF-8
//2.读取一个字符
int read = fr.read();
System.out.println((char) read);
//3.释放资源
fr.close();
}
}
4.使用转换流InputStreamReader解决中文问题
InputStreamReader extends Reader
1.构造方法
public InputStreamReader(InputStream in, String charsetName); 指定编码
public InputStreamReader(InputStream in); 默认和IDEA一样(UTF-8)
2.使用InputStreamReader读取不同编码的文件(代码演示)
public class InputStreamReaderDemo {
public static void main(String[] args) throws Exception {
//1.创建一个InputStreamReader对象
// InputStreamReader isr = new InputStreamReader(new FileInputStream("gbk.txt"), "gbk");
InputStreamReader isr = new InputStreamReader(new FileInputStream("utf8.txt"), "gbk");
//2.读
int read = isr.read();
System.out.println((char) read);
read = isr.read();
System.out.println((char) read);
read = isr.read();
System.out.println((char) read);
//2.释放资源
isr.close();
}
}
5.使用转换流OutputStreamWriter写中文
OutputStreamWriter extends Writer
1.构造方法
public OutputStreamWriter(InputStream in, String charsetName); 指定编码
public OutputStreamWriter(InputStream in); 默认和IDEA一样UTF-8编码
public static void main(String[] args) throws Exception {
//1.写文件
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("utf8.txt"),"UTF-8");
// OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("gbk.txt"),"gbk");
//2.写数据
osw.write('你');
osw.write('好');
//3.释放资源
osw.close();
}
}
6.练习:转换文件编码****************
练习:将GBK编码的文件,转换为UTF-8编码的文本文件
public class TestDemo {
public static void main(String[] args) throws Exception {
// 6.练习:转换文件编码**********************
// 需求:将GBK编码的文本文件,转换为UTF-8编码的文本文件。
//1.创建一个转换输入流
InputStreamReader isr = new InputStreamReader(new FileInputStream("test_gbk.txt"),"gbk");
//2.创建一个转换输出流
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("test_utf.txt"), "utf-8");
//3.一边读 一边写
int ch = 0;
while ((ch = isr.read()) != -1) {
osw.write(ch);
}
//4.释放资源
osw.close();
isr.close();
}
}
三.序列化流
1.什么是序列化流
字符流:以字符为单位操作数据
字节流:以字节为单位操作数据
序列化流:也叫对象流,以对象为单位操作数据 序列化流:对象的输出流,写对象
ObjectOutputStream
反序列化流:对象的输入流,读对象
ObjectInputStream
2.ObjectOutputStream的介绍和使用
a.构造方法
public ObjectOutputStream(OutputStream out);
创建序列化流需要普通的字节输出流
b.序列化操作的前提
被序列化的对象必须使用java.io.Serializable接口
c.序列化操作(代码演示)
public class Dog implements Serializable{
int age;
String name;
int legs;
public Dog() {
}
public Dog(int age, String name, int legs) {
this.age = age;
this.name = name;
this.legs = legs;
}
@Override
public String toString() {
return "Dog{" +
"age=" + age +
", name='" + name + '\'' +
", legs=" + legs +
'}';
}
}
public class ObjectStreamDemo {
public static void main(String[] args) throws IOException {
//1.创建一个ObjectOutputStream对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("1.txt"));
//3.写对象
//NotSerializableException
Dog d = new Dog(2, "旺财", 3);
oos.writeObject(d);
//3.释放资源
oos.close();
}
}
3.ObjectInputStream的介绍和使用
ObjectinputStream对象的输入流,也叫反序列化流
a.构造方法
public ObjectInputStream(InputStream in); 创建反序列化时需要普通的字节输入流
b.反序列操作(正常演示)
public class ObjectStreamDemo01 {
public static void main(String[] args) throws Exception {
//1.创建ObjectInputStream对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("1.txt"));
//2.读对象
Object obj = ois.readObject();
System.out.println(obj);
//3.释放资源
ois.close();
}
}
c.反序列化操作的两种错误演示
i.InvalidClassException 无效类异常
原因:序列化之后,反序列化之前,修改了类的源码
ii.ClassNotFoundException 找不到类异常
原因:序列化之后,反序列化之前,直接删除类
d.序列化流通过对比类的序列化版本号,判断类是否有效的
每一个实现java.io.Serializable接口会自动生成一个版本号,当内容发生改变之后,版本号会重新计算,生成新的版本号,所以,反序列化时对比流中对象的版本号和本地类的对象的版本号,不一致就抛出异常 e.序列化版本号允许程序员自己管理,但是版本自己管理必须是以下格式:
public static final long seriralVersionUID = 值;
f.关键字: transient (''括起来表示默认值)
transient关键字修饰成员变量
作用:被transient修饰的成员和以前没有任何区别!!!
当序列化流序列化该对象时,忽略有transient标记的成员变量
4.;练习:如果需要序列化多个对象怎么操作?********************
解决方案:创建一个结合,把多个对象保存到这个集合对象中
public class ObjectStreamTestDemo {
public static void main(String[] args) throws Exception {
readArrayList();
}
public static void readArrayList() throws Exception {
//1.创建反序列化流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("dogs.txt"));
//2.读对象
ArrayList<Dog> dogs = (ArrayList<Dog>) ois.readObject();
for (Dog dog : dogs) {
System.out.println(dog);
}
//3.释放资源
ois.close();
}
public static void writeArrayList() throws IOException {
//1.有多个对象
Dog d1 = new Dog(1, "旺1财", 2);
Dog d2 = new Dog(2, "旺2财", 3);
Dog d3 = new Dog(3, "旺3财", 4);
Dog d4 = new Dog(4, "旺4财", 5);
//2.要将这些对象保存到集合中
ArrayList<Dog> dogs = new ArrayList<Dog>();
Collections.addAll(dogs, d1, d2, d3, d4);
//3.只要序列化这个集合对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("dogs.txt"));
//4.写对象
oos.writeObject(dogs);
//5.释放资源
oos.close();
}
}
四.打印流
1.打印流PrintStream的介绍
a.所见即所得
b.打印流不会抛出IOException
2.PrintStream的构造和常用方法
构造方法:
public printStream(String pathname);
public printStream(File file);
public publicStream(OutputStream out);
成员方法:
public void print(任意数据类型); 打印数据但是不换行
public void println(任意数据类型); 打印数据且换行
public class PrintStreamDemo {
public static void main(String[] args) throws Exception {
//1.创建一个打印流
PrintStream ps = new PrintStream("print.txt");
// PrintStream ps = new PrintStream(new File("print.txt"));
// PrintStream ps = new PrintStream(new FileOutputStream("print.txt"));
//2.打印 (特点:所见即所得)
// ps.print('a');
// ps.print(97);
// ps.print("java");
// ps.print(3.14);
// ps.print(true);
// ps.print(false);
ps.println('a');
ps.println(97);
ps.println("java");
ps.println(3.14);
ps.println(true);
ps.println(false);
//2.释放资源
ps.close();
}
}
3.扩展_修改打印流的流向
打印流:System.out.println(); 之前一直在用
public class PrintStreamDemo02 {
public static void main(String[] args) throws Exception {
// PrintStream ps = System.out;
System.out.println("HelloWorld");
System.out.println("HelloWorld");
System.out.println("HelloWorld");
System.out.println("HelloWorld");
//修改System.out这个打印的方向
PrintStream ps = new PrintStream("111.txt");
// System.out = ps;
System.setOut(ps);
//测试
System.out.println("Java");
System.out.println("Java");
System.out.println("Java");
System.out.println("Java");
System.out.println("Java");
}
}
总结:
-[] 能够使用字节缓冲流中流读取数据到程序
BufferedInputStream
-[] 能够使用字节缓冲流写出数据到文件
BufferedOutputStream
-[] 能够明确字符缓冲流的作用和基本用法
-[] 能够使用缓冲流的特殊功能
BufferedReader
public String readLine();
BufferedWriter
public void newLine();
-[] 能够阐述编码表的意义
-[] 能够使用转换流读取指定编码的文本文件
InputStreamReader FileReader
-[] 能够使用转换流写入指定编码的文本文件
OutputStreamWriter FileWriter
-[] 能够使用序列化流写出对象到文件
ObjectOutputStream
-[] 能够使用反序列化流读取文件到程序中
ObjectInputStream