天天看點

Thinking in java 瑣碎知識點之 I/O流 、對象序列化

Java I/O流 、對象序列化

1、File類

   此類的執行個體可能表示(也可能不表示)實際檔案系統對象,如檔案或目錄。

   File類可以建立、删除和重命名檔案和目錄,但是File不能通路檔案本身的内容,這要使用IO流。

   File對象的createNewFile()方法在磁盤上建立真實的檔案

2. io流分類

  讀取一個檔案,輸入流  

  寫出一個檔案,輸出流

  字元流:專門用于讀寫文本檔案的(記事本可以正常打開),字元流操作的最小資料單元是16位的字元 查詢本機上的編碼表(GBK)

  問題?word excel是不是文本檔案

  常見的文本檔案: .txt  .java  html  xml  sql

  位元組流:操作的最小單元是8位的位元組,最小的存儲機關1個位元組

          1個位元組8個二進制位

 任意檔案

   問題?能操作檔案夾嗎 (不能)

3、Java中的io繼承體系

   繼承體系,類與類之間繼承關系,子類中的共性提取成的父類

   父類中定義的功能,是這個體系中的最共性的内容

   學習一個繼承體系的時候,找父類去看,建立子類對象

   字元流:

     輸出流,寫入檔案的抽象基類(體系中的最高層的父類) Writer

     輸入流,讀取檔案的抽象基類 Reader

   位元組流:

     輸出流,寫入檔案的抽象基類 OutputStream

     輸入流,讀取檔案的抽象基類 InputStream

4. 字元流的輸入流(讀檔案)使用

   字元流讀取檔案

     查閱API文檔找到了Reader

       read()方法讀取單個字元,傳回int值?

       傳回的int值,是讀取到的字元的ASCII碼值

       read()方法,每執行一次,自動的向後讀取一個字元

       讀取到檔案末尾的時候,得到-1的值

     找到Reader類的子類 FileReader

      FileReader(String fileName) 傳遞字元串檔案名

      read(字元數組)

      傳回int值

      數組中存儲的就是檔案中的字元

      int傳回值,讀到末尾就是-1

      int傳回數組中,讀取到的字元的有效個數

      好處:可以提高讀取的效率

      注意問題:

        出現異常:XXXX拒絕通路

 A.操作,确認是不是操作的檔案

 B.登入windows的賬戶是不是管理者,不是管理者登入的,不能操作c盤下的檔案

    其他盤符是可以的

5.字元流的輸出流(寫檔案)使用

    字元流寫檔案

    查閱API文檔,找到了使用的子類,FileWriter

FileWriter(String fileName) 

          根據給定的檔案名構造一個 FileWriter 對象。

void write(String str) 是FileWriter類的父類的方法

   記住:Java中字元流寫資料,不會直接寫到目的檔案中,寫到記憶體中

         想将資料寫到目的檔案中,重新整理,刷到目的文本中

flush()重新整理

   記住:流對象中的功能,調用了Windows系統中的功能來完成

         釋放掉作業系統中的資源,簡稱:關閉流

close方法,關閉流之前,關閉的時候,先要重新整理流中的資料

但是,如果寫檔案的資料量很大,寫一句刷一句才好

    看到了父類中的write方法

    記住:IO操作,需要關閉資源,關閉資源的時候,開了幾個流,就要關閉幾個流

    單獨的進行關閉資源,單獨寫try catch,保證每一個流都會被關閉

6. 複制文本檔案

讀取源檔案 FileRreader

寫入到目的檔案 FileWriter

   兩種檔案複制方式,分别計算時間

讀一個字元,寫一個字元

第一個數組,寫一個數組

   利用緩沖區複制檔案

        第一行,寫一行的操作

7. 字元流的緩沖區對象(也叫處理流、包裝流)

   利用數組提升了檔案的讀寫速度,運作效率提升了

   我們想到了效率問題,Java工程師(Oracle),也想到了提升效率

   寫好了字元流的緩沖區對象,目的提供流的寫,讀的效率

   寫入流的緩沖區對象BufferedWriter

BufferedWriter(Writer out)

參數Writer類型的參數,傳遞的參數是Writer類的子類對象

緩沖區,提供流的寫的效率,哪個流的效率 FileWriter

         void newLine() 寫一個換行,具有跨平台

不用newLine()方法,也可以實作換行 \r\n

\r\n Windows下的換行符号

\n Linux下的換行符号

   讀取流的緩沖區對象BufferedReader

      BufferedReader(Reader in) 

      參數Reader類型參數,傳遞的是Reader類的子類對象

      緩沖區,提供流的讀的效率,哪個流的效率FileRreader

      讀取一行的方法 readLine(),檔案末尾傳回null

      不是末尾傳回字元串 String 

8、位元組流

9. 處理流PrintStream流的用法

10、重定向标準輸入輸出流

   Java的标準輸入輸出分别通過System.in和System.out來代表,預設情況下它們分别代表鍵盤和顯示器

   System類提供了重定向标準輸入輸出的方法

Scanner和IO流接(BufferedReader)受鍵盤輸入的比較(BufferedReader輸入都被當成String對象,BufferedReader不能讀取基本類型輸入項)

11、RandomAccessFile對象

12、對象序列化

在Java中如果需要将某個對象儲存到磁盤或者通過網絡傳輸,那麼這個類應該實作Serializable标記接口或者Externalizable接口之一

序列化的步驟:

a、建立一個ObjectOutputstream處理流(必須建立在其它結點的基礎上)對象

b、調用ObjectOutputstream對象的writeObject方法輸出可序列化對象

從二進制流中恢複Java對象的反序列化步驟(按照實際寫入的順序讀取):

a、建立一個ObjectInputStream處理流(必須建立在其它結點的基礎上)對象

b、調用ObjectInputstream對象的readObject方法輸出可序列化對象(該方法傳回的是Object類型的Java對象)

(反序列化恢複Java對象時必須要提供java對象所屬類的class檔案)

注:如果一個可序列化對象有多個父類,則該父類要麼是可序列化的,要麼有無參的構造器,因為反序列化機制要恢複其關聯的父類執行個體

而恢複這些父類執行個體有兩種方式:使用序列化機制、使用父類無參的構造器

采用Java序列化機制時,隻有當第一次調用writeObject輸出某個對象時才會将該對象轉換成位元組序列寫到ObjectOutputStream

在後面程式中如果該對象的屬性發生了改變,即再次調用writeObject方法輸出該對象時,改變後的屬性不會被輸出

如果父類沒有實作Serializable接口,則其必須有預設的構造函數(即沒有參數的構造函數)

但是若把父類标記為可以串行化,則在反串行化的時候,其預設構造函數不會被調用。

這是因為Java 對串行化的對象進行反串行化的時候,直接從流裡擷取其對象資料來生成一個對象執行個體,而不是通過其構造函數來完成。

13、自定義序列化

 在屬性前面加上transient關鍵字,可以指定Java序列化時無需理會該屬性值,由于transient修飾的屬性将被完全隔離在序列化機制外,

 這會導緻在反序列化恢複Java對象時無法取得該屬性值。

 實作自定義序列化要重寫類的如下方法:

 private void writeObject(java.io.ObjectOutputStream out) throws IOException;

 private void readObject(java.io.ObjectInputStream in) throws IOException,ClassNotFoundException;

 還有種更徹底的序列化機制可以在序列化某對象時替換該對象,此種情況下應為序列化類提供如下特殊方法:

 ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;

 Java的序列化機制保證在序列化某個對象之前,先調用對象的writeReplace()方法,如果該方法傳回另一個Java對象,

 則系統轉為序列化另一個對象。

 小結:系統在序列化某個對象之前,先會調用該對象的如下兩個方法:

 writeReplace和writeObject,系統先調用被序列化對象的writeReplace方法,如果傳回另一個Java對象,則再次調用該java對象的writeReplace方法....

 直到該方法不在傳回一個對象為止,程式最後調用該對象的writeObject方法來儲存該對象的狀态

 與writeReplace方法相對的有一個方法可以替代原來反序列化的對象

 即:private Object readResolve() throws ObjectStreamException;

 這個方法會緊接着readObject之後被立即調用,該方法的傳回值會代替原來反序列化的對象,而原來readObject反序列化的對象會被立即丢棄

 (此方法在序列化單例類、早期枚舉類時很有用)

14、另一種序列化機制:Java類實作Externalizable接口

    兩種序列化機制的差別:

      實作Serializable接口      

      系統自動存儲必要資訊   

      Java内建支援,易于實作隻需實作該接口即可            

      無須任何代碼支援    

      性能略差  

  實作Externalizable接口 

  程式員決定需要存儲哪些資訊

 僅僅提供兩個空方法實作該接口必須為兩個空方法提供實作

 類中必須存在一個無參構造方法

 性能略高

Java新I/O 

15、Charset對象

    Java提供了Charset來處理位元組序列和字元序列之間的轉換關系,該類包含了用于建立解碼器和編碼器的方法

    例程:CharsetTransformTest.java

16、Buffer(緩沖)抽象基類

    常用子類ByteBuffer,這些Buffer的子類不是通過構造器建立而是通過static xxxBuffer allocate(int capacity)來建立一個容量為capacity的xxxBuffer對象。Buffer中包含兩個重要的方法flip(該方法将limit設定為position所在位置,position設定       為0,)和clear(将position設為0,limit設為 capacity)。flip為從Buffer中讀取資料做好準備,而clear是為向Buffer中裝入資料做好準備

例程:BufferTest.java

17、Channel(通道)

    程式不能直接通路Channel中放入資料,Channel隻能和Buffer進行互動,發送到Channel中的資料必須先放到Buffer對象中,程式再将Buffer的輸入寫入Channel。而從Channel中讀取資料也必須先讀到Buffer中,程式再從Buffer中取出這些資料。

例程:FileChannelTest.java