1.流的编码
字符编码:就是一套自然语言的字符域二进制数之间的对应规则。编码表(字符集):生活中文字和计算机中二进制的对应规则。
常见字符集有ASCII字符集(ASCII编码)、GBK字符集(GBK编码、最常用的中文码表)、Unicode字符集(UTF8编码、UTF16编码、UTF32编码)。UTF8时电子邮件、网页以及其他存储或传送文字的应用中、有限采用的编码。
1.1字符通向字节的桥梁——OutputStreamWriter/InputStreamReader
OutputStreamWriter可以使用指定的charset将要写入流中的字符编码成字节。
java.io.OutputStreamWriter extends Writer
构造方法:
OutputStreamWriter(OutputStream out) 创建使用默认字符编码的OutputStreamWriter
OutputStreamWriter(OutputStream out, String charsetName)
参数:
String charsertName:指定编码表名称,不区分大小写, 可以是utf-8、bgk等,不指定默认使用UTF-8
使用步骤:
1.创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称。
2.使用OutputStreamWriter对象中的方法write,把字符转换为字节存储缓冲区中(编码)
3.使用Output’StreamWriter对象中的方法flush,把内存缓冲区中的字节刷新到文件中(使用字节流写字节的过程)
4.释放资源。
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("C:\\a.txt","utf-8");
osw.write("你好");
ows.flush();
osw.close();
InputStreamReader,是字节刘翔字符流的桥梁,使用指定的charset读取字节并为其解码为字符。
构造方法
InputStreamReader(InputStream in)
InputStreamReader(InputStream in, Stream charsetName)
使用步骤:
1.创建InputStreamReader对象,构造方法中传递字节输入流和指定字节编码表名称;
2.使用InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称;
3.释放资源
注意:构造方法中指定的编码表名称要和文件的编码相同,否则乱码。
InputStreamReader isr = new InputStreamReader(new FileInputStream,"UTF-8");
int len = 0;
while((len = isr.read())!=-1) {
System.out.println(len);
}
isr.close();释放资源
1.2 综合练习——转换文件编码
步骤:
1.创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称GBK;
2.创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称UTF-8;
3.使用InputStreamReader对象中的方法read读取文件;
4.使用OutputStreamWriter对象中的方法write,把读取的数据写入到文件中。
5.释放资源;
2.序列化
把对象以流的方式,写入到文件中保存,叫写对象,也叫对象的序列化,writeObejct§;把文件中保存的对象,以流的方式读取出来,叫做读对象,也就对象的反序列化。
Object obj = new Person(“Lucy”,10);
2.1对象的序列化流
java.io.ObjectOutputStream extends OutputStream(OutputStream out)
特有成员方法:
void writeObject(Object obj) 将指定的对象写入ObjectOutputStream
注意:要进行序列化和反序列化的类必须实现Serializable接口,就会给类添加一个标记(标记型接口,即接口中无任何方法) ,当我们进行序列化和反序列化的时候,就会检测类上是否有这个标记。有的化就可以序列化和反序列化;没有的话就会抛出一个NotSerializableException异常。
使用步骤:
0.先对要进行写入/写出的对象的类,实现序列化接口;
1.创建ObejctOutputStream对象,构造方法中传递字节输出流;
2.使用ObjectOutputStream对象中的方法writeObject,把对象写入到文件中;
3.释放资源;
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\a.txt");
oss.writeObject(new Person("Lucy",22));
oss.close();
2.2对象的反序列化流
java.io.ObjectInputStream extends InputStream
构造方法:
ObjectInputStream(InputStream in)
特有成员方法:
Object readObject() 从ObjectInputStream读取对象;
使用步骤:
1.创建ObjectInputStream对象,构造方法中传递字节输入流;
2.使用ObjectInputStream对象中的方法readObject读取保存对象的文件。
3.释放资源;
4.使用读取出来的对象;
反序列化过程中两个常见异常:
(1)readObject方法声明抛出了ClassNotFoundException(class文件找不到异常)。当不存在对象的class文件时抛出异常。
(2)当JVM反序列化对象时,能找到class文件,但class文件在序列化对象后发生修改,那么反序列化操作也会失败,抛出一个InvalidClassException异常。发生这个异常原因常常有三个:该类的序列版本号与从流中读取的类描述的版本号不匹配;该类包含未知数据类型;该类没有可访问的无参数构造方法。
即解决方法是,Person实现类添加了Serializable接口后,在Person实现类中添加:
private static final long serialVersionUID = -234L;//静态、final、long
因此,反序列化也有两个前提:
1.类必须实现Serializable;
2.必须存在类对应的class文件;
2.3瞬态关键字
static关键字:静态关键字
今天太优先于非静态加载到内存中(静态优先于对象进入到内存中)。被static修饰的成员变量不能被序列化。
transient关键字:瞬态关键字
被transient修饰成员变量,不能被序列化,但没有static的性质。
2.4 序列化集合——案例
/*
序列化集合
当我们想在文件中保存多个对象时,可以把多个对象存储到一个集合中,对集合进行序列化和反序列化;
步骤:
1.定义一个存储Person对象的ArrayList集合;
2.往ArrayList集合中存储Person对象;
3.创建一个序列化流ObjectOutputStream对象;
4.使用ObjectOutputStream对象中的方法writeObject,对集合进行序列化;
5.创建一个反序列化ObjectinputStream对象;
6.使用反序列化对象方法readObject读取文件中保存的集合;
7.把Object类型的集合转换为ArrayList类型;
8.遍历ArrayList集合
9.释放资源;
*/
ArrayList<Person> list = new ArrayList<>();
list.add(new Person("Lucy",22));
list.add(new Person("nancy",23));
//省略。。。。。。
Object o = ois.readObject();
ArrayList<Person> list2 = (ArrayList<Person>)o;//强转
for(Person p : list2) {
System.out.println();
}
3.打印流
为其他输出流添加功能,使它们能够方便打印各种数据值。例如System.out就是一个打印流。
java.io.PrintStream: 打印流
PrintStream特点:
1.只负责数据输出,不负责数据的读取;
2.与其他输出流不同,PrintStream永远不会抛出IOException;
3.有特有的方法:
void print(任意类型值)
void println(任意类型值,并换行)
构造方法:
PrintStream(File file):输出的目的地是一个文件
PrintStream(OutputStream out):输出的目的地是一个字节输出流
PrintStream(String fileName)输出的目的地是一个文件路径
PrintStream extends OutputStream 因此继承父类的成员方法。
注意:
如果使用继承父类的write方法写数据,那么查看数据时候会自动查询编码表;如果使用自己特有的方法print/println方法写数据,写数据会原样输出(97就是97,a就是a)。
打印流的流向,是可以被改变的。
可以改变输出语句的目的地,输出语句默认在控制台进行输出。
使用System.setOut方法改变输出语句的目的地,改编为参数中传递的打印目的地
static void setOut(PrintStream out)
例子
PrintStream ps = new PrintStream("D:\\a.txt");
System.setOut(ps);
System.out.println("我打印流的目的地是a.txt");
ps.close();