(四)IO流——物件流、列印流
物件流:
使用物件流之前,很明顯需要一個自定義的物件
可是普通的自定義類建立的物件並不能被物件流序列化
我們要讓這個自定義類實現一個Serializable介面(Serializable是一個標誌性介面,介面中無任何內容)
例:(省略了構造方法、get/set方法、toString方法)
public class Person implements Serializable{
private String name;
private int age;
}
ObjectOutputStream(物件輸出流):
物件序列化,將物件以流的形式儲存到資料夾的過程
public ObjectOutputStream(OutputStream out) 建立指定位元組輸出流的物件輸出流物件
File f = new File("a.txt");
FileOutputStream fos = new FileOutputStream(f);
ObjectOutputStream oos = new ObjectOutputStream(fos);
void writeObject(Object obj) 儲存物件到流關聯的檔案中
File f = new File("b.txt"); FileOutputStream fos = new FileOutputStream(f); ObjectOutputStream oos = new ObjectOutputStream(fos); Person p = new Person("jack",22); oos.writeObject(p); oos.close();
這樣就完成了物件的序列化到b.txt:
ObjectOutputStream物件輸出流輸出的物件檔案就是亂碼,只能用物件流檢視檔案內容
ObjectInputStream(物件輸入流):
物件反序列化,將檔案中物件以流的形式讀取出來的過程
public ObjectInputStream(InputStream in) 建立指定位元組輸入流物件的物件輸入流物件
File f = new File("b.txt"); FileInputStream fis = new FileInputStream(f); ObjectInputStream ois = new ObjectInputStream(fis);
public final Object readObject () 讀取一個物件
File f = new File("b.txt");
FileInputStream fis = new FileInputStream(f);
ObjectInputStream ois = new ObjectInputStream(fis);
Object obj = ois.readObject();
System.out.println(obj); //輸出:Person{name='jack', age=22}
fis.close();
當儲存好物件後,若對類的內容作了修改,且沒有重新使用物件輸出流輸出一次關聯檔案
則readObject()方法讀取到的關聯檔案時就會出現InvalidClassException異常
因為每次修改類內容(無論是,包括修飾符、成員變數、成員方法)都會改變類中的一個serialVersionUID值
然後再次讀取該物件檔案時,就會出現序列化不同的異常
若不想因為對類內容作了一些微小修改,而導致原始檔不能被讀取的問題
可以在類中固定好serialVersionUID值,且設定為私有final靜態的!
public class Person implements Serializable{
private String name;
private int age;
private static final long serialVersionUID = 12345L; //固定serialVersionUID為任意一個值
}
若物件序列化時,部分成員變數中的資訊,不想被writeObject寫進檔案中
1.可以將成員變數設定為static靜態成員變數
這樣改成員變數就儲存在類中,建立物件時不會被物件序列化輸出到檔案中
public class Person implements Serializable{
private String name;
private int age1;
private static final long serialVersionUID = 12345L;
private static double high ;
}
弊端:設定為靜態後,反序列化該物件檔案確實不會顯示此成員變數
可是所有Person類物件的high屬性都是固定的,這樣很不靈活、很不實用
2.使用transient關鍵字
使用該關鍵字修飾的成員變數,能保證成員變數的值不被序列化到檔案中,只會短暫儲存在記憶體中
public class Person implements Serializable{
private String name;
private int age1;
private static final long serialVersionUID = 12345L;
private transient int high ; //transient修飾了high屬性
}
做個測試:使用ObjectOutputStream輸出帶有transient關鍵字修飾的成員變數
File f = new File("a.txt");
FileOutputStream fos = new FileOutputStream(f);
ObjectOutputStream oos = new ObjectOutputStream(fos);
Person p = new Person("jack",20,22); //寫入被transient關鍵字修飾的high屬性為22
oos.writeObject(p);
oos.close();
然後再用ObjectInputStream檢視該物件是否包含該成員變數的資訊
File f = new File("a.txt");
FileInputStream fis = new FileInputStream(f);
ObjectInputStream ois = new ObjectInputStream(fis);
Object obj = ois.readObject();
Person p = (Person)obj; //將Object物件強轉為Person物件
System.out.println(p.getHigh()); //輸出:0
fis.close();
列印流:
PrintStream類:
public PrintStream(File file) 使用指定的File物件建立列印流物件
File f = new File("b.txt");
PrintStream ps = new PrintStream(f);
public PrintStream(String fileName) 使用指定的檔名字串建立列印流物件
PrintStream ps = new PrintStream("b.txt");
PrintStream類的print()和println()方法中可以輸出基本資料型別
其實常用System.out.println輸出語句就是一個列印流的println方法
只是建立了PrintStream物件時,指定了File物件,呼叫print方法時輸出的物件變成了文字檔案
PrintStream consolePs = System.out; //用PrintStream物件接受系統輸出
PrintStream ps = new PrintStream("b.txt");
System.setOut(ps); //設定系統輸出流為ps
System.out.println("你好"); //這個"你好" 會列印在b.txt文字內
System.setOut(consolePs); //設定系統輸出流為consolePs
System.out.println("你好"); //這個"你好" 會列印在控制檯