IO流:BufferedReader
BufferedReader:
-
这是一个缓冲流,它有一个方法:readLine()
-
如果要使用这个流则必须是纯文本的文件
-
它不是一个节点流,是一个包装流所以在创建它的对象的时候需要先创建一个Reader系列的节点流再使用它进行包装
实例代码如下:
public void testReadLine() throws IOException {
//创建IO流
BufferedReader br = new BufferedReader(new FileReader("resources/test.txt"));
//IO流操作
String line;
//按行进行读取
while((line = br.readLine()) != null){
System.out.println(line);
}
//关闭IO流
br.close();
}
数据IO流
DataOutputStream
数据的输出流,允许应用程序以适当的方式把
基本Java数据类型写入输出流中,然后,在需要时应用程序可以使用数据输入流(DataInputStream)把数据读入。
DataInputStream
数据的输入流,允许应用程序以与机器无关的方式从底层输入流中
读取基本Java数据类型。应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。
注意:
1.Java基本数据类型:8种,而基本Java数据类型:8种 + String
2.数据IO流不是节点流,需要包装一个节点流
DataOutputStream实例代码:
public void save() throws IOException {
//有如下数据需要进行保存,保存完的数所需要可以进行恢复
String name = "张三";
int age = 30;
char gender = 'M';
double sal = 5500.0;
//创建IO流
DataOutputStream dos = new DataOutputStream(new FileOutputStream("resources/data.dat"));
//IO流操作
dos.writeUTF(name);
dos.writeInt(age);
dos.writeChar(gender);
dos.writeDouble(sal);
//关闭IO流
dos.close();
}
DataInputStream实例代码:
public void resume() throws IOException {
//创建IO流
DataInputStream dis = new DataInputStream(new FileInputStream("resources/data.dat"));
//IO流操作
String name = dis.readUTF();
int age = dis.readInt();
char gender = dis.readChar();
double sal = dis.readDouble();
System.out.println("name = " + name);
System.out.println("age = " + age);
System.out.println("gender = " + gender);
System.out.println("sal = " + sal);
//关闭IO流
dis.close();
}
注意:在使用DataInputStream进行读操作时需要保证与写的顺序要一致
对象IO流:ObjectInpuStream、ObjectOutputStream
前面说所的数据IO流它只能处理基本java类型,如果要处理一个对象则需要使用对象IO流
对象IO流有两个:
ObjectOutputStream:输出对象,序列化(对象-->字节)
ObjectInputStream:读取对象,反序列化(字节-->对象)
如:有下面这个类的对象
public class Student implements Serializable {
private int id;
private String name;
private String address;
public Student(int id, String name, String address) {
this.id = id;
this.name = name;
this.address = address;
}
public Student() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
接下来 我们创建一个Student类型的对象并把对象的信息写到指定的文件当中进行序列化
public void save() throws IOException {
Student student = new Student(1,"张三","学府路8888号");
//创建IO流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("resources/student.dat"));
//IO流操作
oos.writeObject(student);
//关闭IO流
oos.close();
}
注意:在使用ObjectOuptStream写入对象的信息到文件的时候一定要求对象所属的类需要implements Serializable,表示这个类的对象是可序列化的。
java.io.Serializable接口:它是一个标识型接口,没有抽象方法等,只需要在声明类的时候写上implements Serializable即可
当我们写入到文件中后,我们要把这个对象读取出来则可以如下:
public void Read() throws IOException, ClassNotFoundException {
//创建IO流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("resources/student.dat"));
//IO流操作
Student student = (Student)ois.readObject();
System.out.println(student.getName() + ":" + student.getAddress());
//关闭IO流
ois.close();
}
注意:在对象的序列化与反序列化之间要有一个serialVersionUID这个需要关注,因为在序列化对象的信息后,在反序列回来前又可能类的信息被修改了
这个时候反序列化回来的时候会报错
我们一般在实现Serializable接口时,加上一个serialVersionUID(序列化版本ID)
如果我们的类上没有加上这个,则只要类重新编译过后,原来序列化的数据就无法反序列化(当没有手动上上序列化版本ID的情况下,每次编译都会自动随机产生一个序列货版本的值)
当我们加上了这个序列化版本ID,只要这个值不变,原来序列化的数据依然可以反序列化
当我们对象中某些属性是不希望去序列化的,这个时候如何操作?
我们可以在类中对指定的不需要序列化的属性加上 transient 标识,它表示临时的瞬时的
注意:一个类中的静态变量是不会被序列化的
序列化接口:Externalizable
java.io.Externalizable
这个接口的原码写法如下:
public interface Externalizable extends java.io.Serializable {
void writeExternal(ObjectOutput out) throws IOException;
void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}
注意:这个接口与Serializable不同之处是,它是有两个抽象方法的
writeExternal:这个方法用来确定哪些成员变量需要序列化,以及序列化的顺序
readExternal:这个方法用来确定如何进行反序列化
当使用了Externalizable去实现了序列化及反序列化的操作后,对象中的static属性、transient属性都可以进行序列化及反序列化
如下代码:
1.声明一个类
public class Student2 implements Externalizable{
private static String school;
private int id;
private String name;
private transient int age;
public Student2(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public Student2() {
}
public static String getSchool() {
return school;
}
public static void setSchool(String school) {
Student2.school = school;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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;
}
@Override
public String toString() {
return id + "," + name + "," + age + "," + school;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(school);
out.writeInt(id);
out.writeUTF(name);
out.writeInt(age);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
school = in.readUTF();
id = in.readInt();
name = in.readUTF();
age = in.readInt();
}
}
2.对以上的类进行序列化与反序列化
public class Testio13{
@Test
public void save() throws IOException {
Student2 student2 = new Student2(1,"张三",23);
student2.setSchool("清华大学");
//创建IO流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("resources/student2.dat"));
//IO操作
oos.writeObject(student2);
//关闭IO
oos.close();
}
@Test
public void read() throws IOException, ClassNotFoundException {
//创建IO流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("resources/student2.dat"));
//IO操作
Student2 stu2 = (Student2)ois.readObject();
System.out.println(stu2);
}
}
System中IO流对象:System.in、System.out
System.in ----> InputStream
System.out ----> PrintStream
PrintStream:它是包装输出流,提供打印的表示形式。
1.它是不会抛出IOException异常的
2.它会自动刷新
如果其他IO流,可以手动刷新,使用flush()
System.in、System.out等对象在System类中是public static final的常量,并且被初始化为null,那这些对象的值在什么时候进行的赋值呢?
注意:在类中有一个静态代码块
private static native void registerNatives();
static{
registerNatives();
}
这里在初始化的时候是使用c语言来实现的
上面说这些对象都是静态的常量,但是它们还是会有setIn(),setOut()等方法,其设置值的过程也是调用了非JAVA的代码来实现的
那么我们可以使用set方法来控制输出的位置,比如我们控制其输出到指定的文件(System.out默认是控制台)
public void test01() throws FileNotFoundException {
System.setOut(new PrintStream(new FileOutputStream("resources/print.txt")));
System.out.println("你好");
System.out.println("中国");
System.out.println("hello world");
}
对于System.in的操作也是一样
public void test02() throws FileNotFoundException {
System.setIn(new FileInputStream("resources/print.txt"));
Scanner scanner = new Scanner(System.in);
System.out.println(scanner.nextLine());
System.out.println(scanner.nextLine());
System.out.println(scanner.nextLine());
scanner.close();
}