目 录
一、数据输入输出流
1.DataOutputStream
2.DataInputStream
二、序列化和反序列化
1.ObjectOutputStream
2.ObjectInputStream
3.Serializable 接口
(1)说明
(2)实例
4.序列化版本号
(1)说明
(2)实例
5.transient 关键字
三、打印流
1.PrintStream
2.PrintWriter
一、数据输入输出流
1.DataOutputStream
- 数据字节数输出流;
- 将 Java 程序中的数据直接写入文件,直接是二进制;
- 效率较高,因为不需要转码;
- 只能由 DataInputStream 读取。
java">public class DataOutputStreamTest {public static void main(String[] args) {try (DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream("D:\\Test.txt"))) {byte b = 127;short s = 100;int i = 999;long l = 666666;float f = 2.1F;double d = 520.1314;char c = 'a';String str1 = "女也不爽,士贰其行。";String str2 = "士也罔极,二三其德。";boolean boo = true;dataOutputStream.writeByte(b);dataOutputStream.writeShort(s);dataOutputStream.writeInt(i);dataOutputStream.writeLong(l);dataOutputStream.writeFloat(f);dataOutputStream.writeDouble(d);dataOutputStream.writeChar(c);dataOutputStream.write("\n".getBytes());dataOutputStream.writeChars(str1);dataOutputStream.writeUTF(str2);dataOutputStream.writeUTF("\n");dataOutputStream.writeBoolean(boo);} catch (FileNotFoundException e) {throw new RuntimeException(e);} catch (IOException e) {throw new RuntimeException(e);}}
}
2.DataInputStream
- 数据字节输入流;
- 特用来读取 DataOutputStream 流写入的文件;
- 读取的顺序要与写入的顺序一致。
java">public class DataInputStreamTest {public static void main(String[] args) {try (DataInputStream dataInputStream = new DataInputStream(new FileInputStream("D:\\Test.txt"))) {System.out.println(dataInputStream.readByte()); // 127System.out.println(dataInputStream.readShort()); // 100System.out.println(dataInputStream.readInt()); // 999System.out.println(dataInputStream.readLong()); // 666666System.out.println(dataInputStream.readFloat()); // 2.1System.out.println(dataInputStream.readDouble()); // 520.1314System.out.println(dataInputStream.readChar()); // aSystem.out.println(dataInputStream.readUTF()); // 女也不爽,士贰其行。System.out.println(dataInputStream.readUTF()); // 士也罔极,二三其德。System.out.println(dataInputStream.readBoolean()); // true} catch (FileNotFoundException e) {throw new RuntimeException(e);} catch (IOException e) {throw new RuntimeException(e);}}
}
二、序列化和反序列化
1.ObjectOutputStream
- 对象字节输出流;
- 完成对象序列化,可以将 JVM 中的 Java 对象序列化到文件或者网络中;
- 序列化是将 Java 对象转换为字节序列的过程。
java">public class ObjectOutputStreamTest {public static void main(String[] args) {try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\Test.txt"))) {String str = "落霞与孤鹜齐飞,秋水共长天一色。";objectOutputStream.writeObject(str);} catch (IOException e) {throw new RuntimeException(e);}}
}
2.ObjectInputStream
- 对象字节输入流;
- 完成反序列化,可以将字节序列转换为 JVM 中的 Java 对象。
java">public class ObjectInputStreamTest {public static void main(String[] args) {try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\Test.txt"))) {Object o = objectInputStream.readObject();System.out.println(o);} catch (FileNotFoundException e) {throw new RuntimeException(e);} catch (IOException e) {throw new RuntimeException(e);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}}
}
3.Serializable 接口
(1)说明
- 参与序列化和反序列化的对象必须实现 java.io.Serializable 接口;
- 该接口是一个标志接口,其内部没有任何方法。
(2)实例
java">public class ObjectOutputStreamTest {public static void main(String[] args) {try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\Test.txt"))) {Student s1 = new Student("王勃", 29);Student s2 = new Student("李白", 32);Student s3 = new Student("杜甫", 33);ArrayList<Student> arrayList = new ArrayList<>();arrayList.add(s1);arrayList.add(s2);arrayList.add(s3);objectOutputStream.writeObject(arrayList);} catch (IOException e) {e.printStackTrace();}}
}
java">public class Student {private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}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;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age && Objects.equals(name, student.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}
}
若没有实现 Serializable 接口,则会报不可序列化异常,因此需要实现这个标志接口。
public class Student implements Serializable {
……
}
java">public class ObjectInputStreamTest {public static void main(String[] args) {try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\Test.txt"))) {Object o = objectInputStream.readObject();System.out.println(o);// [Student{name='王勃', age=29}, Student{name='李白', age=32}, Student{name='杜甫', age=33}]} catch (FileNotFoundException e) {throw new RuntimeException(e);} catch (IOException e) {throw new RuntimeException(e);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}}
}
4.序列化版本号
(1)说明
- 当 Java 程序实现了 Serializable 接口,编译器会自动给该类添加一个【序列化版本号】;
- Java 首先通过类名,其次通过序列化版本号区分 Class 版本;
- 每次改动程序代码,会生成一个新的序列化版本号;
- 如果确定类还是原来的类,本身合法,而想要保证序列化、反序列化成功,则需要定义序列化版本号并赋值。
(2)实例
java">public class Student implements Serializable {private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}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;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age && Objects.equals(name, student.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}
}
java">public class ObjectOutputStreamTest {public static void main(String[] args) {try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\Test.txt"))) {Student s1 = new Student("王勃", 29);Student s2 = new Student("李白", 32);Student s3 = new Student("杜甫", 33);ArrayList<Student> arrayList = new ArrayList<>();arrayList.add(s1);arrayList.add(s2);arrayList.add(s3);objectOutputStream.writeObject(arrayList);} catch (IOException e) {e.printStackTrace();}}
}
java">public class ObjectInputStreamTest {public static void main(String[] args) {try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\Test.txt"))) {Object o = objectInputStream.readObject();System.out.println(o);// [Student{name='王勃', age=29}, Student{name='李白', age=32}, Student{name='杜甫', age=33}]} catch (FileNotFoundException e) {throw new RuntimeException(e);} catch (IOException e) {throw new RuntimeException(e);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}}
}
对此序列化和反序列化都正常,但是之后若是对 Student 类进行修改(例如:新增属性及相关方法)后再进行反序列化操作,会出现 java.io.InvalidClassException 异常。
所以需要指定序列化版本号,就保证了反序列化的正常进行。
public class Student implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
……
}
5.transient 关键字
其修饰的属性不会参与序列化。
java">public class Student implements Serializable {@Serialprivate static final long serialVersionUID = 1L;private String name;private transient int age;public Student(String name, int age) {this.name = name;this.age = age;}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;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age && Objects.equals(name, student.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}
}
用 transient 修饰 age 属性,序列化和反序列化后,可以看到所有 Student 对象的年龄都是 0 。
三、打印流
1.PrintStream
- 字节打印流;
- 提供便捷的打印方法和格式化输出,主要打印内容到文件或控制台;
- 可以直接输出各种数据类型;
- 可以自动刷新和自动换行;
- 支持字符串转义;
- 自动根据环境选择合适的编码方式;
- 不需要手动刷新,自动刷新;
- 常用方法有:print()、println()、printf();
- 调用 printf 方法可以格式化输出:
- 【%s】表示字符串;
- 【%d】表示整数;
- 【%f】表示小数(【%.2f】表示保留两位小数 );
- 【%c】表示字符。
2.PrintWriter
- 字符打印流;
- 需要手动刷新;
- 常用方法有:print()、println()、printf()。