標籤:style blog io color os ar 使用 java sp
操作對象
ObjectInputStream、ObjectOutputStream
被操作的對象需要實現Serializable(標記介面)
ObjectOutputStream 將 Java 對象的基礎資料型別 (Elementary Data Type)和圖形寫入 OutputStream。可以使用 ObjectInputStream 讀取(重構)對象。通過在流中使用檔案可以實現對象的持久儲存。如果流是網路通訊端流,則可以在另一台主機上或另一個進程中重構對象。
對象的預設序列化機制寫入的內容是:對象的類,類簽名,以及非瞬態和非靜態欄位的值。其他對象的引用(瞬態和靜態欄位除外)也會導致寫入那些對象。可使用引用共用機制對單個對象的多個引用進行編碼,這樣即可將對象的圖形恢複為最初寫入它們時的形狀。
對象的序列化
public static void writeobj()throws IOException {//如果是txt檔案的話,是一堆。。。,一般尾碼名都是objectObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.object"));//很多架構都是儲存的,建立會很麻煩,一般都是讀取oos.writeObject(new Perman("a",1));//僅僅是把Object Storage Service出硬碟,讓其生命週期延長oos.close();//完成了對象的序列化,被序列化的對象必須實現Serializable}
注意writeObject寫入的:
將指定的對象寫入 ObjectOutputStream。對象的類、類的簽名,以及類及其所有超類型的非瞬態和非靜態欄位的值都將被寫入。
對象的還原序列化
存的目的是為了讀。FileInputStream可以讀出來對象的資料,但是無法拼成一個對象
ObjectInputStream 對以前使用 ObjectOutputStream 寫入的基本資料和對象進行還原序列化。
也就是說:ObjectInputStream只能讀ObjectOutputStream寫入的
readobject()一次,讀一個對象
public static void readobj()throws IOException, ClassNotFoundException {//如果是txt檔案的話,是一堆。。。,一般尾碼名都是objectObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.object"));Perman p = (Perman)ois.readObject();//必須拋異常System.out.println(p.getName()+":"+p.getAge());ois.close();}
一般用於特定的資料庫連接對象,不想建立,想留存的對象
關於Serializable
序列化運行時使用一個稱為 serialVersionUID 的版本號碼與每個可序列化類別相關聯,該序號在還原序列化過程中用於驗證序列化對象的寄件者和接收者是否為該對象載入了與序列化相容的類。
一個實現該介面後,對象會被序列化,帶著一個ID號,當類改變時(private int age : public int age),讀取的時候,會判斷接收的類對象(修改後)與讀取到的類對象(修改前)是否是同一個版本,不是會拋異常。InvalidClassException,而ID號是根據類的特徵和簽名,完成了一個ID號的定義
PS:Serializable介面作用:用於給被序列化的類加入ID,判斷和對象是否是同一個版本
如果可序列化類別未顯式聲明 serialVersionUID,則序列化運行時將基於該類的各個方面計算該類的預設 serialVersionUID 值,如“Java(TM) 對象序列化規範”中所述。不過,強烈建議 所有可序列化類別都顯式聲明 serialVersionUID 值,原因是計算預設的 serialVersionUID 對類的詳細資料具有較高的敏感性,根據編譯器實現的不同可能千差萬別,這樣在還原序列化過程中可能會導致意外的 InvalidClassException
。因此,為保證 serialVersionUID 值跨不同 java 編譯器實現的一致性,序列化類別必須聲明一個明確的 serialVersionUID 值。還強烈建議使用private
修飾符顯示聲明 serialVersionUID(如果可能),原因是這種聲明僅應用於直接聲明類 -- serialVersionUID 欄位作為繼承成員沒有用處。數組類不能聲明一個明確的 serialVersionUID,因此它們總是具有預設的計算值,但是數組類沒有匹配 serialVersionUID 值的要求。
可序列化類別可以通過聲明名為 "serialVersionUID"
的欄位(該欄位必須是靜態 (static)、最終 (final) 的long
型欄位)顯式聲明其自己的 serialVersionUID:
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
任意存取修飾詞
class Perman implements Serializable{private static final long serialVersionUID = 845645641123231l;//瞎寫+l//如果對象想要序列化,就必須實現介面,標記private String name;private int age;//.....}public static void readobj()throws IOException, ClassNotFoundException {//如果是txt檔案的話,是一堆。。。,一般尾碼名都是objectObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.object"));Perman p = (Perman)ois.readObject();//必須拋異常System.out.println(p.getName()+":"+p.getAge());ois.close();}
這樣修改後,類改變也沒有問題,因為ID號沒變,照樣可以讀取出來,儲存的對象
關鍵字transient(暫時的)
在寫入對象的時候,對象中的一些資料不想寫如硬碟,使用該關鍵字
class Perman implements Serializable{private static final long serialVersionUID = 845645641123231l;//瞎寫+lprivate transient String name;private int age; ......}
transient:非靜態資料,被序列化
IO包的其他類:
RandomAccessFile:隨機訪問檔案,自身具備讀寫的方法。
通過skipBytes(int x),seek(int x)來達到隨機訪問。
管道流:PipedInputStream 和 PipedOutputStream
輸入輸出可以直接進行串連,通過集合線程使用
RandomAccessFile
不是IO體系中的子類。
特點:
1.既能讀,又能寫
2.該對象中記憶體維護了一個數組,通過指標可以運算元組中的元素
3.可以通過getFilePointer方法擷取指標的位置,通過seek方法設定指標的位置
4.因為是byte數組,其實該對象就是位元組輸入資料流和輸出資料流封裝
5.局限性,從建構函式可以看出,源和匯只能是檔案
此類的執行個體支援對隨機訪問檔案的讀取和寫入。隨機訪問檔案的行為類似儲存在檔案系統中的一個大型 byte 數組。存在指向該隱含數組的游標或索引,稱為檔案指標;輸入操作從檔案指標開始讀取位元組,並隨著對位元組的讀取而前移此檔案指標。如果隨機訪問檔案以讀取/寫入模式建立,則輸出操作也可用;輸出操作從檔案指標開始寫入位元組,並隨著對位元組的寫入而前移此檔案指標。寫入隱含數組的當前末尾之後的輸出操作導致該數組擴充。該檔案指標可以通過getFilePointer
方法讀取,並通過 seek
方法設定。
構造方法摘要 |
RandomAccessFile(File file,String mode) 建立從中讀取和向其中寫入(可選)的隨機訪問檔案流,該檔案由 File 參數指定。 |
RandomAccessFile(String name,String mode) 建立從中讀取和向其中寫入(可選)的隨機訪問檔案流,該檔案具有指定名稱。 |
mode 參數指定用以開啟檔案的訪問模式。允許的值及其含意為:
值 |
含意 |
"r" |
以唯讀方式開啟。調用結果對象的任何 write 方法都將導致拋出 IOException 。 |
"rw" |
開啟以便讀取和寫入。如果該檔案尚不存在,則嘗試建立該檔案。 |
"rws" |
開啟以便讀取和寫入,對於 "rw",還要求對檔案的內容或中繼資料的每個更新都同步寫入到底層存放裝置。 |
"rwd" |
開啟以便讀取和寫入,對於 "rw",還要求對檔案內容的每個更新都同步寫入到底層存放裝置。 |
寫入
public static void RandomAccessFileDemo() throws IOException {//檔案不存在,建立,存在,不建立RandomAccessFile raf = new RandomAccessFile("ran.txt", "rw");//拋異常raf.write("ASD".getBytes());//使用平台的預設字元集將此 String 編碼為 byte 序列,並將結果儲存到一個新的 byte 數組中。raf.writeInt(97);//可以寫基礎資料型別 (Elementary Data Type)位元組,int佔4個位元組 三個空格+araf.close();}
讀取和隨機讀取
public static void read()throws IOException {RandomAccessFile raf = new RandomAccessFile("ran.txt", "r");byte[] by = new byte[6];raf.read(by);String name = new String(by);int t = raf.readInt();System.out.println("name"+name);System.out.println("t = "+t);raf.seek(2*7);//設定指標的位置,可以實現隨機讀取System.out.println("pointer : "+raf.getFilePointer());raf.close();}public static void RandomAccessFileDemo() throws IOException {//檔案不存在,建立,存在,不建立RandomAccessFile raf = new RandomAccessFile("ran.txt", "rw");//拋異常raf.write("阿薩德".getBytes());//使用平台的預設字元集將此 String 編碼為 byte 序列,並將結果儲存到一個新的 byte 數組中。raf.writeInt(97);//可以寫基礎資料型別 (Elementary Data Type)位元組,int佔4個位元組 三個空格+araf.write("阿德".getBytes());raf.writeInt(98);raf.close();}
隨機寫入和細節
public static void randomwrite() throws IOException{RandomAccessFile raf = new RandomAccessFile("ran.txt", "rw");//拋異常/*raf.write("覆蓋".getBytes());raf.write(102);raf.close();//如果直接寫,會覆蓋原來的 阿薩的值*/raf.seek(3*8);//想往哪寫就寫,也就意味著可以修改某個值//因為有些人名的字數不同,但是最多16位元組raf.write("覆蓋".getBytes());raf.write(102);raf.close();//PS:一般是集合多線程同時往檔案中寫入資料,控制每個線程寫入不同位置的資訊(t1線程寫[1-100]位元組內,t2線程寫[101-200]位元組)}
JAVA學習第五十六課 — IO流(十)對象的序列化和還原序列化 & RandomAccessFile