1.InputStreamReader
字节流通向字符的桥梁
所有已实现的接口:
直接已知子类:
将字节输入流转换为字符输入流
使用指定的字符编码表(可显式指定也可接受默认),读取字节并将其解码为字符
1.1构造函数
InputStreamReader(InputStream in):创建一个使用默认字符集的InputStreamReader
InputStreamReader(InputStream in,Charset chas):创建一个使用指定字符集的InputStreamReader
1.2 方法
int read():读取单个字符
int read(char[] chs,int index,int len): 将字符读入数组中的某一部分
1.3 使用步骤
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Test{
public static void main(String[] args) throws IOException {
//关联文件和字节输入流对象
InputStream in=new FileInputStream("a.txt");
//转换流对象,字节--->字符
InputStreamReader isr=new InputStreamReader(in,"GBK");//utf-8时是问号,不写也可正常输出
int ch=0;
while((ch=isr.read())!=-1)
System.out.print((char)ch);
isr.close();
in.close();
}
}
运行结果:
2.OutputStreamWriter
字符流通向字节流的桥梁。
所有已实现的接口:
Closeable, Flushable, Appendable
直接已知子类:
作用就是利用字节流作为底层输出流然后构建字符输出流,字符输出流输出字符到流中,然后通过指定的字符集把流中的字符编码成字节输出到字节流中,其作用就是一个桥梁,使得双方链接起来。
2.1构造函数
OutputStreamWriter(OutputStream out):创建使用默认字符编码的 OutputStreamWriter。
OutputStreamWriter(OutputStream out,Charset cs):创建使用给定字符集的 OutputStreamWriter。
2.2 方法
void write(int c):写入单个字符
void write(char[] chs,int index,int len):写入字符数组的某一部分
2.3使用步骤
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
public class Test{
public static void main(String[] args) throws IOException {
OutputStream out=new FileOutputStream("a.txt");
OutputStreamWriter osw=new OutputStreamWriter(out,"GBK");
osw.write("我在呢!");
osw.close();
out.close();
}
}
运行结果:
2.4总结
父类:OutputStreanWriter、InputStreamReader,字符和字节之间的桥梁,源流:字节流+编码表
子类:FileWriter、FileReader,操作文件的便捷类,使用默认的编码表时,可不用父类。
字节->字符,读,输入流,InputStreamReader
字符->字节,写,输出流,OutputStreamWriter
3.ObjectOutputStream
序列化流
所有已实现的接口:
Closeable, DataOutput, Flushable, ObjectOutput, ObjectStreamConstants
用于向文件中写入对象,将 Java 对象的基本数据类型和图形写入 OutputStream。可
可以使用 ObjectInputStream 读取(重构)对象。
只能将支持 java.io.Serializable 接口的对象写入流中,若未实现,会出现NotSerializableException。
3.1构造方法
ObjectOutpputStream(OutputStream out):创建写入指定 OutputStream 的 ObjectOutputStream
3.2 方法
void writeObject(Object obj):将指定的对象写入 ObjectOutputStream
void writeInt(int i):写入int值
3.3 将一个对象存储到持久化设备上的步骤
- 明确存储对象的文件
- 给操作文件对象加入写入对象的功能
- 调用写入对象的方法
- 关闭资源
import java.io.Serializable;
public class Person implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
String name;
int age;
public Person(String name,int age) {
this.name=name;
this.age=age;
}
public String toString() {
return "name:"+this.name+",age:"+this.age;
}
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class Test{
public static void main(String[] args) throws IOException {
FileOutputStream fos=new FileOutputStream("a.txt");
ObjectOutputStream oos=new ObjectOutputStream(fos);
oos.writeObject(new Person("zhangsan",30));
oos.close();
fos.close();
}
}
运行结果:
4.ObjectInputStream
反序列化流,对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。
所有已实现的接口:
Closeable, DataInput, ObjectInput, ObjectStreamConstants
用于从流中读取对象
ObjectOutputStream 和 ObjectInputStream 分别与 FileOutputStream 和 FileInputStream 一起使用时,可以为应用程序提供对对象图形的持久存储。
只有支持 java.io.Serializable 或 java.io.Externalizable 接口的对象才能从流读取。
4.1构造函数
ObjectInputStream(FileInputStream in):创建从指定 InputStream 读取的 ObjectInputStream。
4.2方法
Object readObject():从 ObjectInputStream 读取对象。
int readInt(): 读取一个 32 位的 int 值。
4.3 对象的反序列化步骤
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class Test{
public static void main(String[] args) throws IOException, ClassNotFoundException {
FileInputStream fis=new FileInputStream("a.txt");
ObjectInputStream ois=new ObjectInputStream(fis);
Person p=(Person)ois.readObject();
System.out.println(p.toString());
ois.close();
fis.close();
}
}
运行结果:
5.Serializable接口
java.io.Serializable
类通过实现 java.io.Serializable 接口以启用其序列化功能。
未实现此接口的类将无法使其任何状态序列化或反序列化。
可序列化类的所有子类型本身都是可序列化的。
序列化接口没有方法或字段,仅用于标识可序列化的语义。
5.1 常见问题
- 先写对象
- 再读对象
- 接着改该Person类
- 再读对象,出现InvalidClassException
原因:
- 该类的序列版本号与从流中读取的类描述符的版本号不匹配。
- 该类包含位置数据类型
- 该类没有可访问的无参构造方法
解决办法:给一个默认的序列化ID
6.transient
瞬态关键字
当一个类的独享需要被序列化时,某些属性不需要序列化,可用关键字transient修饰。
静态修饰的属性也不会被序列化。
- 因为序列化是把对象数据持久化存储,静态属于类加载时的数据,不会被序列化。
private static String name;
private transient int age;