JAVA 特殊操作流 物件序列化 Properties
阿新 • • 發佈:2022-05-08
標準輸入輸出流
System類中有兩個靜態的成員變數:
- public static final InputStream in:標準輸入流。通常該流對應於鍵盤輸入或由主機環境或使用者指定的另一個輸入源
- public static final PrintStream out:標準輸出流。通常該流對應於顯示輸出或主機環境或使用者指定的另一個輸出目標
自己實現鍵盤錄入資料:
- BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
寫起來太麻煩,Java就提供了一個類實現鍵盤錄入
- Scanner sc=new Scanner(System.in);
標準輸入流的用法:
1 import java.io.BufferedReader; 2 import java.io.FileReader; 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.InputStreamReader; 6 import java.util.Scanner; 7 8 /* 9 public static final InputStream in:標準輸入流。通常該流對應於鍵盤輸入或由主機環境或使用者指定的另一個輸入源 10 */ 11 publicclass SystemInDemo { 12 public static void main(String[] args) throws IOException { 13 //public static final InputStream in:標準輸入流 14 // InputStream is = System.in; 15 16 // int by; 17 // while((by=is.read())!=-1) { 18 // System.out.print((char)by);19 // } 20 /* 21 a 22 a 23 b 24 b 25 中 26 ?? 27 */ 28 29 //如何把位元組流轉換為字元流?用轉換流 30 // InputStreamReader isr=; 31 //使用字元流能不能夠實現一次讀取一行資料呢?可以 32 //但是,一次讀取一行資料的方法時字元緩衝輸入流的特有方法 33 // BufferedReader br=new BufferedReader(isr); 34 35 //用一步來實現 36 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 37 38 System.out.println("請輸入一個字串"); 39 String line = br.readLine(); 40 System.out.println("你輸入的字串是:" + line); 41 42 System.out.println("請輸入一個整數:"); 43 int i = Integer.parseInt(br.readLine()); //要得到什麼型別的字串,就要用它對應的包裝類的方法轉換 44 System.out.println("你輸入的整數是:" + i); 45 46 //自己實現鍵盤錄入資料太麻煩了,所以Java就提供了一個類供我們使用 47 // Scanner sc = new Scanner(System.in); 48 49 } 50 }
輸出語句的本質:是一個標準的輸出流
- PrintStream ps = System.out;
- PrintStream類有的方法,System.out都可以使用
1 import java.io.PrintStream; 2 3 /* 4 public static final PrintStream out:標準輸出流。通常該流對應於顯示輸出或主機環境或使用者指定的另一個輸出目標 5 */ 6 public class SystemOutDemo { 7 public static void main(String[] args) { 8 // public static final PrintStream out:標準輸出流 9 PrintStream ps = System.out; 10 11 // 能夠方便地列印各種資料值 12 // ps.print("hello"); 13 // ps.print(100); 14 15 // ps.println("hello"); 16 // ps.println(100); 17 18 // System.out的本質是一個位元組輸出流 19 System.out.println("hello"); 20 System.out.println(100); 21 22 System.out.println(); 23 // System.out.print();//報錯 24 25 } 26 }
列印流
列印流分類:
- 位元組列印流:PrintStream
- 字元列印流:PrintWriter
列印流特點:
- 只負責輸出資料,不負責讀取資料
- 有自己的特有方法
位元組列印流
- PrintStream(String fileName):使用指定的檔名建立新的列印流
- 使用繼承父類的方法寫資料,檢視的時候會轉碼;使用自己的特有方法寫資料,檢視的資料原樣輸出
位元組列印流用法:
1 import java.io.IOException; 2 import java.io.PrintStream; 3 4 /* 5 列印流特點: 6 只負責輸出資料,不負責讀取資料 7 有自己的特有方法 8 9 位元組列印流 10 PrintStream(String fileName):使用指定的檔名建立新的列印流 11 */ 12 13 public class PrintStreamDemo { 14 public static void main(String[] args) throws IOException { 15 // PrintStream(String fileName):使用指定的檔名建立新的列印流 16 PrintStream ps = new PrintStream("..\\hello java\\ps.txt"); 17 18 // 寫資料 19 // 位元組輸出流有的方法 20 // ps.write(97);//a 21 22 // 使用特有方法 23 // ps.print(97);//97 24 // ps.println();//換行 25 // ps.print(98);//98 26 27 ps.println(97); 28 ps.println(98); 29 30 // 釋放資源 31 ps.close(); 32 } 33 }
字元列印流PrintWriter的構造方法:
1 import java.io.FileWriter; 2 import java.io.IOException; 3 import java.io.PrintWriter; 4 5 /* 6 字元列印流PrintWriter的構造方法: 7 8 PrintWriter (String fileName)使用指定的檔名建立一個新的PrintWriter,而不需要自動執行重新整理 9 10 PrintWriter(Writer out,boolean autoFlush)建立一個新的PrintWriter 11 1.out:字元輸出流 12 2.antoFlush:一個布林值,如果為真,則println,printf,或format方法將重新整理輸出緩衝區 13 */ 14 public class PrintWriterDemo { 15 public static void main(String[] args) throws IOException { 16 // PrintWriter (String fileName)使用指定的檔名建立一個新的PrintWriter,而不需要自動執行重新整理 17 // PrintWriter pw=new PrintWriter("..\\hello java\\pw.txt"); 18 19 // pw.write("hello"); 20 // pw.write("\r\n");//加換行符 21 // pw.flush();//字元流,需要重新整理,否則不出來 22 // 23 // pw.write("world"); 24 // pw.write("\r\n"); 25 // pw.flush(); 26 27 // pw.println("hello"); 28 /*相當於: 29 pw.write("hello"); 30 pw.write("\r\n"); 31 */ 32 // pw.flush();//還是需要重新整理,比較麻煩 33 // pw.println("world"); 34 // pw.flush(); 35 36 // PrintWriter(Writer out,boolean autoFlush)建立一個新的PrintWriter 37 PrintWriter pw = new PrintWriter(new FileWriter("..\\hello java\\pw.txt"), true);// 實現自動重新整理 38 // PrintWriter pw=new PrintWriter(new FileWriter("..\\hello java\\pw.txt"),false); 39 40 pw.println("hello"); 41 /*相當於: 42 pw.write("hello"); 43 pw.write("\r\n"); 44 pw.flush(); 45 */ 46 pw.println("world"); 47 48 pw.close(); 49 50 } 51 }
案例:複製Java檔案(列印流改進版)
需求:把模組目錄下的PrintStreamDemo.java複製到模組目錄下的Copy.java
思路:
- 根據資料來源建立字元輸入流物件
- 根據目的地建立字元輸出流物件
- 讀寫資料,復值檔案
- 釋放資源
1 import java.io.BufferedReader; 2 import java.io.BufferedWriter; 3 import java.io.FileReader; 4 import java.io.FileWriter; 5 import java.io.IOException; 6 import java.io.PrintWriter; 7 8 /* 9 案例:複製Java檔案(列印流改進版) 10 11 需求:把模組目錄下的PrintStreamDemo.java複製到模組目錄下的Copy.java 12 13 思路: 14 1. 根據資料來源建立字元輸入流物件 15 2. 根據目的地建立字元輸出流物件 16 3. 讀寫資料,復值檔案 17 4. 釋放資源 18 */ 19 public class CopyJavaDemo { 20 public static void main(String[] args) throws IOException { 21 /*//1. 根據資料來源建立字元輸入流物件 22 BufferedReader br=new BufferedReader(new FileReader("..\\hello java\\PrintStreamDemo.java")); 23 //2. 根據目的地建立字元輸出流物件 24 BufferedWriter bw=new BufferedWriter(new FileWriter("..\\hello java\\Copy.java")); 25 //3. 讀寫資料,復值檔案 26 String line; 27 while((line=br.readLine())!=null) { 28 bw.write(line); 29 bw.newLine(); 30 bw.flush(); 31 } 32 //4. 釋放資源 33 br.close(); 34 bw.close();*/ 35 36 // 1. 根據資料來源建立字元輸入流物件 37 BufferedReader br = new BufferedReader(new FileReader("..\\hello java\\PrintStreamDemo.java")); 38 // 2. 根據目的地建立字元輸出流物件 39 PrintWriter pw = new PrintWriter(new FileWriter("..\\hello java\\Copy.java"), true); 40 41 String line; 42 while ((line = br.readLine()) != null) { 43 pw.println(line); 44 } 45 // 4. 釋放資源 46 br.close(); 47 pw.close(); 48 49 } 50 }
物件序列化流
物件序列化:就是將物件儲存到磁碟中,或者在網路中傳輸物件
這種機制就是使用一個位元組序列表示一個物件,該位元組序列包含:物件的型別、物件的資料和物件中儲存的屬性等資訊
位元組序列寫到檔案之後,相當於檔案中持久儲存了一個物件的資訊
反之,該位元組序列還可以從檔案中讀取回來,重構物件,對它進行反序列化
要實現序列化和反序列化就要使用物件序列化流和物件反序列化流:
- 物件序列化流:ObjectOutputStream
- 物件反序列化流:ObjectInputStream
物件序列化流
物件序列化流:ObjectOutputStream
- 將Java物件的原始資料型別和圖形寫入OutputStream。可以使用ObjectInputStream讀取(重構)物件。可以通過使用流的檔案來實現物件的持久儲存。如果流是網路套接字流,則可以在另一個主機上或另一個程序中重構物件
構造方法:
- ObjectOutputStream(OutputStream out):建立一個寫入指定的OutputStream的ObjectOutputStream
序列化物件的方法:
- void writeObject(Object obj):將指定的物件寫入ObjectOutputStream
注意:
- 一個物件要想被序列化,該物件所屬的類必須必須實現Serializable介面
- Serializable是一個標記介面,實現該類介面,不需要重寫任何方法
物件序列化的用法:
1 import java.io.Serializable; 2 3 public class Student implements Serializable { 4 private String name; 5 private int age; 6 7 public String getName() { 8 return name; 9 } 10 11 public void setName(String name) { 12 this.name = name; 13 } 14 15 public int getAge() { 16 return age; 17 } 18 19 public void setAge(int age) { 20 this.age = age; 21 } 22 23 public Student(String name, int age) { 24 super(); 25 this.name = name; 26 this.age = age; 27 } 28 29 public Student() { 30 super(); 31 } 32 33 }
1 import java.io.FileOutputStream; 2 import java.io.IOException; 3 import java.io.ObjectOutputStream; 4 5 /* 6 物件序列化流 7 構造方法: 8 9 - ObjectOutputStream(OutputStream out):建立一個寫入指定的OutputStream的ObjectOutputStream 10 11 序列化物件的方法: 12 13 - void writeObject(Object obj):將指定的物件寫入ObjectOutputStream 14 15 NotSerializableException:丟擲一個例項需要一個Serializable介面。序列化執行時或例項的類可能會丟擲此異常 16 類的序列化由實現java.io.Serializable介面的類啟用。不實現此介面的類將不會使用任何狀態序列化或反序列化 17 18 */ 19 public class ObjectOutputStreamDemo { 20 public static void main(String[] args) throws IOException { 21 // ObjectOutputStream(OutputStream out):建立一個寫入指定的OutputStream的ObjectOutputStream 22 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("..\\hello java\\oos.txt")); 23 24 // 建立物件 25 Student s = new Student("小白", 12); 26 27 // void writeObject(Object obj):將指定的物件寫入ObjectOutputStream 28 oos.writeObject(s); 29 30 oos.close(); 31 } 32 }
物件反序列化流:ObjectInputStream
- ObjectInputStream反序列化先前使用ObjectOutputStream編寫的原始資料和物件
構造方法:
- ObjectInputStream(InputStream in):建立從指定的InputStream讀取的ObjectInputStream
反序列化物件的方法:
- Object readObject():從ObjectInputStream讀取一個物件
物件反序列化的用法:
1 import java.io.FileInputStream; 2 import java.io.IOException; 3 import java.io.ObjectInputStream; 4 5 /* 6 物件反序列化流:ObjectInputStream 7 8 - ObjectInputStream反序列化先前使用ObjectOutputStream編寫的原始資料和物件 9 10 構造方法: 11 12 - ObjectInputStream(InputStream in):建立從指定的InputStream讀取的ObjectInputStream 13 14 反序列化物件的方法: 15 16 - Object readObject():從ObjectInputStream讀取一個物件 17 */ 18 public class ObjectInputStreamDemo { 19 public static void main(String[] args) throws IOException, ClassNotFoundException { 20 // ObjectInputStream(InputStream in):建立從指定的InputStream讀取的ObjectInputStream 21 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("..\\hello java\\oos.txt")); 22 23 // Object readObject():從ObjectInputStream讀取一個物件 24 Object obj = ois.readObject();// 丟擲異常 25 26 Student s = (Student) obj;// 向下轉型 27 System.out.println(s.getName() + "," + s.getAge());// 小白,12 28 29 ois.close(); 30 } 31 }
物件系列化流中的三個問題
用物件序列化流序列化了一個物件後,假如我們修改了物件所屬的類檔案,讀取資料會不會出問題呢?
- 會出問題,丟擲InvalidClassException異常
如果出問題了,如何解決呢?
- 給物件所屬的類加一個seriaLVersionUID
private static final long seriaLVersionUID=42L;
如果一個物件中的某個成員變數的值不想被序列化,又該如何實現呢?
- 給該成員變數加transient關鍵字修飾,該關鍵字標記的成員變數不參與序列化過程
1 import java.io.Serializable; 2 3 public class Student implements Serializable { 4 private static final long serialVersionUID = 42L; 5 private String name; 6 // private int age; 7 private transient int age;// 被transient關鍵字修飾的成員變數,不參與序列化過程 8 9 public String getName() { 10 return name; 11 } 12 13 public void setName(String name) { 14 this.name = name; 15 } 16 17 public int getAge() { 18 return age; 19 } 20 21 public void setAge(int age) { 22 this.age = age; 23 } 24 25 public Student(String name, int age) { 26 super(); 27 this.name = name; 28 this.age = age; 29 } 30 31 public Student() { 32 super(); 33 } 34 35 // 修改了類檔案 36 @Override 37 public String toString() { 38 return "Student [name=" + name + ", age=" + age + "]"; 39 } 40 41 }
1 import java.io.FileInputStream; 2 import java.io.FileOutputStream; 3 import java.io.IOException; 4 import java.io.ObjectInputStream; 5 import java.io.ObjectOutputStream; 6 7 /* 8 用物件序列化流序列化了一個物件後,假如我們修改了物件所屬的類檔案,讀取資料會不會出問題呢? 9 java.io.InvalidClassException: 10 當序列化執行時檢測到類中的以下問題之一時丟擲。 11 類的序列版本與從流中讀取的類描述符的型別不匹配 12 該類包含未知的資料型別 13 該類沒有課訪問的無引數建構函式 14 15 Contents2.Student; local class incompatible: 16 stream classdesc serialVersionUID = -7792934128464322290, 17 local class serialVersionUID = -394614500484104815 18 序列化版本號不同 19 20 如果出問題了,如何解決呢? 21 給物件所屬的類加一個值:private static final long seriaLVersionUID=42L; 22 23 如果一個物件中的某個成員變數的值不想被序列化,又該如何實現呢? 24 private transient int age; 25 26 */ 27 28 public class ObjectStreamDemo { 29 public static void main(String[] args) throws IOException, ClassNotFoundException { 30 // write(); 31 read(); 32 33 } 34 35 // 反序列化 36 private static void read() throws IOException, ClassNotFoundException { 37 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("..\\hello java\\oos.txt")); 38 Object obj = ois.readObject(); 39 Student s = (Student) obj; 40 System.out.println(s.getName() + "," + s.getAge()); 41 ois.close(); 42 43 } 44 45 // 序列化 46 private static void write() throws IOException { 47 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("..\\hello java\\oos.txt")); 48 Student s = new Student("小白", 12); 49 oos.writeObject(s); 50 oos.close(); 51 52 } 53 54 }