字符流

#day12-IO(字符流、Properties)
***
##1. 字符流引入
    1. 使用字節流讀寫字符數據產生的問題
        1. 問題1 : 如果寫出的是字符數據, 需要將字符數據轉換成字節數組. 
        2. 問題2 : 如果使用字節流讀取中文數據, 發生了 `亂碼`. 4
    
    2. 集成電路
        1. Cpu、內存、硬盤、IO輸入輸出硬件設備,都是屬於集成電路
        2. 電子元件 : 只有兩種狀態,要麼開要麼關(1和0)
        3. 集成電路就是無數個電子元件組合起來的
        4. 例子
            1. 01001001,8位  -》b  -》 ASCII碼(1個字節,首位是0,只用7位,故表示128個)
            2. encode(編碼): 漢語 -> 0101   編碼,之後方便計算機存儲
            3. decode(解碼): 0101 -> 漢語   解碼,之後方便人類查看
            4. messy code(亂碼) : 用一種A編碼表編碼,用B編碼表解碼

    3. 編碼表介紹
        1. 字節轉成字符的規則
        2. ascii碼錶,128個,佔一個字節:8位,首位是0,後7位表示  (1個字節)
        3. ISO-8859-1(歐碼)256個,佔一個字節:8位全表示        (1個字節)
        4. gbk 2個字節表示1個漢字(windows系統默認)    
        5. utf8  3個字節表示1個漢字(Java開發主流)
##2. 字符流體系
     1. 便捷字符輸入流:FileReader
         0. 需求:使用便捷字符輸入流解決了讀取中文亂碼的問題 
         1. 字符流 : 字節流 + 編碼表 (字節轉字符的規則)                    
            2. FileReader 讀取字符文件的便捷類.  
            3. 特點 : 使用簡單,使用該類無需指定編碼表
            4. 問題: 底層到底有沒有編碼表??? 有的和平臺默認使用編碼表一致,GBK
 
    2. 便捷字符輸入流:FileWriter
        0. 使用便捷字符輸出流寫入英文與中文到文件中 
        1. 寫出數據時, 字符串無需轉換.
        2. 寫出時無需創建File對象, 也無需指定編碼表. 內部使用默認編碼表.

    3. 字符轉換輸出流:OutputStreamWriter
        0. 需求 : 使用 GBK & UTF-8 寫出 hello,我的女神,I love you."
        1. OutputStreamWriter(OutputStream out, String charsetName) 使用指定字符集
        2. 是字符流通向字節流的橋樑    字符流 = 字節流 + 編碼表
        3. 字符流的底層是調用字節流讀寫
        4. 多種方式
            0. FileWriter writer = new FileWriter(path); 
            1. new OutputStreamWriter(FileOutputStream fos);
            2. OutputStreamWriter(OutputStream out, String charsetName)

    4. 字符轉換輸入流:InputStreamReader
        0. 使用InputStreamReader 讀取不同編碼的文件(GBK、UTF-8)
        1. 多種方式
            0. FileReader reader = new FileReader(path);
            1. InputStreamReader(InputStream in) 創建一個使用默認字符集
            2. InputStreamReader(InputStream in, String charsetName) 使用指定字符集

    5. 編解碼和亂碼
        1. 編碼 encode:將字符數據轉換成字節數據. 目的:將字符數據以字節的形式存儲到硬盤文件中.
        2. 解碼 decode:將字節數據轉換成字符數據. 目的:將文件中的字節數據轉換爲字符給程序員查看.
        3. 亂碼 messy code:以A編碼表進行編碼, 以B編碼表進行解碼, 結果就是亂碼. (編碼表和解碼錶對應不上就會產生亂碼)

##3. 複製文件原理
    1. 複製文件的方式
        1. Reader & Writer 字符流複製文本文件 :
            1. FileReader & FileWriter (使用環境默認編碼)
            2. InputStreamReader & OutputStreamWriter (手動指定)
        2. inputStream & 0utputStream
            1. fileInputStream & fileOutputStream
        
    2. 問題:既然字節流和字符流都能複製文件,那它們有何區別?

    3. 原理:
        1. 字符流在複製過程中需要先編碼後解碼,效率低。而且在複製圖片和音視頻文件時也因爲編解碼的原因,容易造成複製之後的文件產生問題。
        2. 字節流複製過程沒有編解碼,效率高,而且不出錯
    4. 總結
        1. 文件複製應該用字節流 
        2. 字符流應該用來讀寫字符數據
## 4. 字符緩衝流
1. BufferedReader & BufferedWriter字符緩衝流
    1.  BufferedWriter : 接收 Writer.
        1. FileWriter(GBK)-> 接收 String / File
         2. OutputStreamWriter (UTF-8)-> 接收 OutputStream-> 傳遞FileOutputStream -> 接收 String / File
         3. 緩衝流寫出三部曲
             1. 寫出     2. 換行    3. 刷新 
     2.  BufferedReader -> 接收 Reader
         1. FileReader(GBK)    -> 接收 String / File
         2. InputStreamReade(UTF-8)-> 接收 InputStream -> 傳遞 FileInputStream -> 接收 String / File 
## 5. 其它流
    1. 打印流
        1. PrintStream
            1. printStream 無需手動關閉和刷新, 數據也可以寫入到文件中 (自動刷新)
            2. PrintStream 爲其他輸出流添加了功能,使它們能夠 `方便地打印各種數據值  print / println` 表示形式。

        2. PrintWriter
            1. PrintWriter 需要 `啓動自動刷新`.
            2. 使用場景:網絡請求 -> request 請求  PrintWriter writer = request.getPrintWriter();  作用: 向網頁中寫出數據.

    2. 序列化和反序列化
        0. 需求:將一個自定義對象存儲到文件中, 並讀取出來.
        1. 概念
            1. 序列化 :將數據結構或對象轉換成二進制串的過程
             2. 反序列化 :二進制串轉換成數據結構或者對象的過程
        2. ObjectOutputStream:將Java的對象寫入到文件中
            1. 異常:NotSerializableException 不能序列化異常
            2. 解決:類通過實現 java.io.Serializable 接口以啓用其序列化功能
            3. Serializable接口
                1. 當一個對象要能被序列化,這個對象所屬的類必須實現Serializable接口
                2. 如果一個接口中沒有任何方法, 那麼該接口就被稱爲 `標識接口`
        3. ObjectInputStream:將文件中的數據讀取爲 Java 對象.
            1. 異常:InvalidClassException 非法類異常(修改該類)
            2. 原因如下:
                1. 該類的序列版本號與從流中讀取的類描述符的版本號不匹配 
                2. 該類包含未知數據類型 
                3. 該類沒有可訪問的無參數構造方法 
            3. Serializable標記接口。該接口給需要序列化的類,提供了一個序列版本號serialVersionUID. 該版本號的目的在於驗證序列化的對象和對應類是否版本匹配。
            4. 解決:在類中顯示聲明一個該對象的 UID 序列號
                * 自動生成,根據該類所有數據計算
        4. 瞬態關鍵字transient
            1. 只要被transient修飾的屬性,在對象序列化時,這個屬性不會被序列化

        5. 練習和應用
            1. 練習:集合(四大名著:作者) 進行序列化和反序列化
            2. 應用:
                1. 序列化這個概念太籠統,說白了就是方便計算機表述,使用010101的方式方便傳輸和存儲。
                2. java 序列化 也是爲了 傳輸和存儲,只是 Serializable 是使用java內部序列化格式。開發中,由於java自身的序列化信息不夠簡潔,一般很少有使用java 序列化對象進行通信的。
##6. Properties類
    1. Properties 類表示了一個持久的屬性集。Properties 可保存在流中或從流中加載。屬性列表中每個鍵及其對應值都是一個字符串。
    2. 特點:
        1. Hashtable的子類,map集合中的方法都可以用。
        2. 該集合沒有泛型。鍵值都是字符串。
        3. 它是一個可以持久化的屬性集。鍵值可以存儲到集合中,也可以存儲到持久化的設備(硬盤、U盤、光盤)上。鍵值的來源也可以是持久化的設備。
        4. 有和流技術相結合的方法。
    3. 方法:
        1. setProperty(String key, String value):調用 Hashtable 的方法 put
        2. stringPropertyNames()返回此屬性列表中的鍵集
        3. getProperty(String key)用指定的鍵在此屬性列表中搜索屬性
        
        4. store(Writer,comments)和 store(OutputStream,comments)
            1. 把集合中的數據,保存到指定的流所對應的文件中,參數comments代表對描述信息
        5. load(InputStream) 和load(Reader) 
            1. 把指定流所對應的文件中的數據,讀取出來,保存到Propertie集合中

    4. 獲取本地系統的屬性集
        1. Properties prop = System.getProperties() 所有屬性集
        2. String country = System.getProperty("user.country") 單個屬性集

##8. Commons-IO 第三方開源包
    1. Apache 軟件基金組織 : Commons-IO      `通用 IO 包`
    2. JAR包
        1. (Java Archive,Java 歸檔文件)是與平臺無關的文件格式,它允許將許多文件組合成一個壓縮文件。
        2. .jar 文件 : 集成了 class 文件. -> class 文件的壓縮包.
    3. 導開源包的步驟
        1. 在工程下創建一個lib文件夾(跟src平級)
        2. 複製 .jar文件到lib目錄
        3. 選中jar包 右單擊  -》 build path
    4. FileUtils 類 :
        1. static void copyFile(File srcFile, File destFile);    複製文件
        2. static void copyDirectoryToDirectory(File srcDir, File destDir).複製文件夾
## 9. 流總結
    1. "字節流 :"
        1. InputStream : 字節輸入流
          |-- FileInputStream
          |-- BufferedInputStream    8k緩存 byte[]
        2. OutputStream : 字節輸出流
          |-- FileOutputStream
          |-- BufferedOutputStream

    2. "字符流 :"
        1. Reader : 字符輸入流
            |-- InputStreamReader : InputStream + 任意編碼表
                |-- FileReader : InputStreamReader + 默認編碼表 (便捷類) 字節流 + 編碼表
            |-- BufferedReader
        2. Writer : 字符輸出流 
            |-- OutputStreamWriter : OutputStream + 任意編碼表
                 |-- FileWriter : OutputStreamWriter + 默認編碼表 (便捷類)字節流 + 編碼表
            |-- BufferedWriter

    3. "請問 : 如何選擇使用那種流呢?"    
        1. "問題1 : 讀取字節數據還是字符數據?"
            1. 字節 : BufferedInputStream / BufferedOutputStream
            2. 字符 : BufferedReader / BufferedWriter
        2. "問題2:複製文件用什麼流?"
            1. 字節流:因爲字符流需要編解碼,效率低,而且可能出錯。
        3. "問題3 : 我是讀還是寫?"
            1. 讀 : BufferedInputStream / BufferedReader
            2. 寫 : BufferedOutputStream / BufferedWriter
        4. "問題4 : 是否需要高效緩衝呢 ?" 當然要.
            1. 是 : 就用對應體系的緩衝流包起來. 緩衝流就是用來裝飾其它流的.所以,要加緩衝,就用緩衝流包裝其它流
        5. "問題5 : 是否需要指定編碼表?"
            1. 需要 , 轉換流. OutputStreamWriter & InputStreamReader
            2. 不需要 , 便捷流. FileWriter & FileReader(默認編碼)

## 快捷鍵
1. 程序崩潰, windows -》ctrl + alt + delete -> 任務管理器 -》結束任務
2. 程序失去響應 -》 底部 ,右單機-》啓動任務管理器


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章