0、序列化
1、创建Person,先执行OOSDemo,再执行OISDemo
--------------(1)对象序列化
-------------(1)对象反序列化
2、转换流
--------------(1)使用转换输出流向文件中写入文本数据:
--------------(2)使用转换流测试读取文本数据:
3、PrintWriter(自动行刷新功能)
-----------(1)缓冲字符输出流:java.io.PrintWriter:
-----------(2)在流链接中使用PW:
1、什么是序列化与反序列化? 序列化是指将对象的状态信息转换为可以存储或传输形式的过程.在序列化期间,对象将其当前状态写入到临时或持久性存储区。 以后可以通过从存储区中读取或者反序列化对象的状态,重新创建该对象。 ①序列化:指把堆内存中的 Java 对象数据,通过某种方式把对象存储到磁盘文件中或者传递给其他网络节点(在网络上传输)。 --------(利用ObjectOutputStream,把对象的信息,按照固定的格式转成一串字节值输出并持久保存到磁盘) ②反序列化:把磁盘文件中的对象数据或者把网络节点上的对象数据,恢复成Java对象模型的过程。 --------(利用ObjectInputStream,读取磁盘中之前序列化好的数据,重新恢复成对象) 2、为什么要做序列化? ①、在分布式系统中,此时需要把对象在网络上传输,就得把对象数据转换为二进制形式,需要共享的数据的 JavaBean 对象,都得做序列化。 ②、服务器钝化:如果服务器发现某些对象好久没活动了,那么服务器就会把这些内存中的对象持久化在本地磁盘文件中(Java对象转换为二进制文件);如果服务器发现某些对象需要活动时,先去内存中寻找,找不到再去磁盘文件中反序列化我们的对象数据,恢复成 Java 对象。这样能节省服务器内存。 3、Java 怎么进行序列化? ①、需要做序列化的对象的类,必须实现序列化接口:Java.lang.Serializable 接口(这是一个标志接口,没有任何抽象方法),Java 中大多数类都实现了该接口,比如:String,Integer ②、底层会判断,如果当前对象是 Serializable 的实例,才允许做序列化,Java对象 instanceof Serializable 来判断。 ③、在 Java 中使用对象流来完成序列化和反序列化:() ObjectOutputStream:通过 writeObject()方法做序列化操作 ObjectInputStream:通过 readObject() 方法做反序列化操作
(1)对象流
ObjectInputStream ObjectOutputStream类分别是InputStream和OutputStream的子类.
对象输出流 使用writeObject(Object obj)方法,将一个对象obj写入到一个文件, 使用readObject()读取一个对象。
(2)构造方法:
ObjectInputStream (InputStream in)
ObjectOutputStream(OutputStream out)
当准备将一个对象写入文件的时候,首先用OutputStream的子类创建一个输出流:
OutputStream outStream = new FileOutputStream("file_name");
ObjectOutputStream objstream = new ObjectOutputStream(outStream);
当使用对象流写入或者读取对象的时候,必须保证该对象是序列化的,这样是为了保证对象能够正确的写入文件,
并能够把对象正确的读回程序。
(3)对象的序列化
将对象转换成二进制数据流的一种实现手段,通过将对象序列化,可以方便的实现对象的传输及保存。 注: ①在Java中提供了ObejctInputStream 和ObjectOutputStream这两个类用于序列化对象的操作。用于存储和读取对象的输入输出流类。 *②要想实现对象的序列化需要实现Serializable接口,但是Serializable接口中没有定义任何的方法,仅仅被用作一种标记,以被编译器作特殊处理。 **③另外,Java.awt包中的Componet类是实现Serializable接口的类,因此程序可以实现把组件写入输出流,然后用输入流读取该组件的克隆。1、创建Person,先执行OOSDemo,再执行OISDemo
对象流-------java.io.ObjectOutputStream和ObjectInputSteam
对象流是一对高级流,在流连接中的作用是进行对象的序列化与反序列化。
(1)对象序列化:将一个java对象按照其结构转换为一组字节的过程
(2)对象反序列化:将一组字节还原为java对象(前提是这组字节是一个对象序列化得到的字节)
对象序列化的流连接操作原理图:package Vdayio;
import java.io.Serializable;
import java.util.Arrays;
public class Person implements Serializable { //①实现Serializable接口, 可序列化接口,规则
static final long serialVersionUID = 1L;//只要版本号没变,就能反序列化(可以进行还原)
private String name;
private int age;
private String gender;//性别
private transient String[] otherInfo;//其他信息
//private int salary;//工资 此时直接执行OISDemo会报错,出现一串数字,版本号不一致
//alt+insert 自动生成代码的快捷键 调用构造器constructor 构造方法里要有这些参数
public Person(String name, int age, String gender, String[] otherInfo) {
this.name = name;
this.age = age;
this.gender = gender;
this.otherInfo = otherInfo;
}
//alt+insert 自动生成代码的快捷键 选择Getter and Setter全选后回车调用构造方法:
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;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String[] getOtherInfo() {
return otherInfo;
}
public void setOtherInfo(String[] otherInfo) {
this.otherInfo = otherInfo;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + ''' +
", age=" + age +
", gender='" + gender + ''' +
", otherInfo=" + Arrays.toString(otherInfo) +
'}';
}
}
(1)对象序列化:
package Vdayio;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class OOSDemo {
public static void main(String[] args) throws IOException {
String name = "苍老师";
int age = 18;
String gender = "女";
String[] otherInfo = {"是一名演员", "来自霓虹", "爱好书法", "广大男性同胞的启蒙老师"};
Person p = new Person(name, age, gender, otherInfo);
System.out.println(p);//输出p.toString()返回值 在Person.java中调用该构造方法
//将该Person对象写入文件person.obj中:
//①因此程序可以实现把组件写入输出流,
FileOutputStream fos = new FileOutputStream("./person.obj");
ObjectOutputStream oos = new ObjectOutputStream(fos);//
oos.writeObject(p);
System.out.println("写出完毕");
oos.close();
}
}
(2)对象反序列化:
package Vdayio;
import java.io.*;
public class OISDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
FileInputStream fis = new FileInputStream("person.obj");
ObjectInputStream ois = new ObjectInputStream(fis);
//抛出异常的操作:alt+enter(回车)。选项第一项add exception...
Person p = (Person)ois.readObject();//①然后用输入流读取该组件的克隆。
System.out.println(p);
ois.close();
}
}
2、转换流
//java IO将流按照读写单位划分为字节流和字符流
字节流:以stream结尾的
字符流:read和writer
//转换流是一对常用的字符流实现类:java.io.InputStreamReader和OutStreamWriter
作用:
①在流连接中衔接其他高级字符流与下面的字节流(这也是转换流名字的由来)。
②负责将字符与对应的字节按照指定的字符集自动转换方便读写操作。
意义:
实际开发中我们还有功能更好用的字符高级流.但是其他的字符高级流都有一个共通点:不能直接连接在字节流上.而实际操作设备的流都是低级流同时也都是字节流.因此不能直接在流连接中串联起来.转换流是一对可以连接在字节流上的字符流,其他的高级字符流可以连接在转换流上.在流连接中起到"转换器"的作用(负责字符与字节的实际转换)
(1)使用转换输出流向文件中写入文本数据:
(1)使用转换输出流向文件中写入文本数据:
package Vdayio;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
public class OSWDemo {
public static void main(String[] args) throws IOException {
//向文件osw.txt中写入文本数据
FileOutputStream fos = new FileOutputStream("osw.txt");
//建议:在创建转换流时通常需要指定第二个参数,明确使用的字符集。
OutputStreamWriter osw = new OutputStreamWriter(fos,StandardCharsets.UTF_8);
// String line = "我可以接受你的所有,所有小脾气";
// byte[] date = line.getBytes(StandardCharsets.UTF_8);
// fos.write(date);
// fos.write("我可以带你去吃很多,很多好东西。".getBytes(StandardCharsets.UTF_8));
// System.out.println("写出完毕!");
//字符输出流支持直接写出字符串的write方法 同上:
osw.write("我可以接受你的所有,所有小脾气。");
osw.write("我可以带你去吃很多,很多好东西。");
System.out.println("写出完毕!");
osw.close();
}
}
(2)使用转换流测试读取文本数据:
package Vdayio;
import java.io.*;
import java.nio.charset.StandardCharsets;
public class ISRDemo {
public static void main(String[] args) throws IOException {
//将osw.txt中的所有内容读取出来并输出到控制台
FileInputStream fis = new FileInputStream("osw.txt");
InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
//读取1个字符,返回的int值内容本质上都是一个char。但是若返回的int为-1则表示读取到了末尾
// int d = isr.read();
// System.out.println((char)d);
//同上:注意print不换行
int d;
while((d = isr.read()) !=-1){
System.out.print((char)d);
}
isr.close();
}
}
3、PrintWriter(自动行刷新功能)
------------------java.io.PrintWriter是具有自动行刷新功能的缓冲字符输出流,内部总是连接BufferedWriter
实际开发中缓冲字符输出流我们都使用它。
特点:
1:可以按行读写字符串
2:可以自动行刷新
3:可以提高写出字符的效率(实际由内部连接的BufferedWriter完整)
①java.io.BufferedWriter和BufferedReader
②缓冲字符流内部也有一个缓冲区,读写文本数据以块读写形式加快效率.并且缓冲流有一个特别的功能:可以按行读写文本数据.
③java.io.PrintWriter具有自动行刷新的缓冲字符输出流,实际开发中更常用.它内部总是会自动连接BufferedWriter作为块写加速使用.
(1):
package Vdayio;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
public class PWDemo {
public static void main(String[] args) throws FileNotFoundException {
//向文件pw.txt中写入文本数据:
PrintWriter pw = new PrintWriter("./pw.txt");
// File file = new File("./pw.txt");//这两句意思同上。
// PrintWriter pw = new PrintWriter(file);
pw.println("该配合你演出的我演视而不见");//输出完毕后按行写在pw.txt中
pw.println("别逼一个最爱你的人即兴表演");
System.out.println("写出完毕!");
pw.close();
}
}
(2)在流链接中使用PW:
PrintWriter的自动行刷新功能:
如果实例化PW时第一个参数传入的是一个流,则此时可再传入一个boolean型的参数,此值为true时就打开了自动行刷新功能。
即:每当我们用PW的println方法写出一行字符串后会自动flush。
package Vdayio;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
public class PWDemo02 {
public static void main(String[] args) throws IOException {
//文件字节输出流(是一个低级流),向文件中写入字节数据
FileOutputStream fos = new FileOutputStream("pw2.txt");
//转换输出流(是一个高级流,且是一个字符流)。1:衔接字符与字节流 2:将写出的字符转换为字节
OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
//缓冲输出流(是一个高级流,且是一个字符流)。块写文本数据加速
BufferedWriter bw = new BufferedWriter(osw);
//具有自动行刷新的缓冲字符输出流:
PrintWriter pw = new PrintWriter(bw,true);//true:[相当于pw.flush();自动行刷新功能]
//:完成简易记事本。控制台输入的每行字符串都按行写入文件。单独输出exit时退出。
Scanner scanner = new Scanner(System.in);
while(true){
String line = scanner.nextLine();
if("exit".equalsIgnoreCase(line)){ //equals:区分大小写 equalsIgnoreCase:不区分大小写
break;
}
pw.println(line);
// pw.flush();//自动行刷新功能
}
pw.close();
}
}



