1. 程式人生 > >10緩沖流、轉換流、序列化流、Files

10緩沖流、轉換流、序列化流、Files

unicode 英文 val edr pub 語言 dex 發生 cte

十、流

10.1 緩沖流

10.1.1 概述

緩沖流是對4個基本的FileXxx流的增強,所以也是4個流,按照數據類型進行分類 字節緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流對象時,會創建一個內置的默認大小的緩沖區數組,通過緩沖區讀寫,減少系統IO次數,從而提高讀寫的效率。

10.1.2 字節緩沖流 構造方法:

構造方法
- public BufferedInputStream(InputStream in) :創建一個 新的緩沖輸入流。
- public BufferedOutputStream(OutputStream out): 創建一個新的緩沖輸出流。

10.1.3 字符緩沖流

構造方法
- public BufferedReader(Reader in) :創建一個 新的緩沖輸入流。
- public BufferedWriter(Writer out): 創建一個新的緩沖輸出流。
特有方法: 字符緩沖流的基本方法與普通字符流調用方式一致,不再闡述, 我們來看它們具備的特有方法。
- BufferedReader:public String readLine(): 讀一行文字。
- BufferedWriter:public void newLine(): 寫一行行分隔符,由系統屬性定義符號。

10.2 轉換流

10.2.1 字符編碼和字符集

字符編碼

計算機中儲存的信息都是用二進制數表示的,而我們在屏幕上看到的數字、英文、標點符號、漢字等字符是二進制數轉換之後的結果。按照某種規則,將字符存儲到計算機中,稱為

編碼 。反之,將存儲在計算機中的二進制數按照某種規則解析顯示出來,稱為解碼 。比如說,按照A規則存儲,同樣按照A規則解析,那麽就能顯示正確的文本f符號。反之,按照A規則存儲,再按照B規則解析,就會導致亂碼現象。

字符編碼Character Encoding : 就是一套自然語言的字符與二進制數之間的對應規則。

字符集

字符集 Charset:是一個系統支持的所有字符的集合,包括各國家文字、標點符號、圖形符號、數字等。

計算機要準確的存儲和識別各種字符集符號,需要進行字符編碼,一套字符集必然至少有一套字符編碼。常見字符集有ASCII字符集、GBK字符集、Unicode字符集等。技術分享圖片

可見,當指定了編碼,它所對應的字符集自然就指定了,所以編碼才是我們最終要關心的。

ASCII字符集
ASCII(American Standard Code for Information Interchange,美國信息交換標準代碼)是基於拉丁字母的一套電腦編碼系統,用於顯示現代英語,主要包括控制字符(回車鍵、退格、換行鍵等)和可顯示字符(英文大小寫字符、阿拉伯數字和西文符號)。
基本的ASCII字符集,使用7位(bits)表示一個字符,共128字符。ASCII的擴展字符集使用8位(bits)表示一個字符,共256字符,方便支持歐洲常用字符。
ISO-8859-1字符集
拉丁碼表,別名Latin-1,用於顯示歐洲使用的語言,包括荷蘭、丹麥、德語、意大利語、西班牙語等。
ISO-5559-1使用單字節編碼,兼容ASCII編碼。
GBxxx字符集
GB就是國標的意思,是為了顯示中文而設計的一套字符集。
GB2312:簡體中文碼表。一個小於127的字符的意義與原來相同。但兩個大於127的字符連在一起時,就表示一個漢字,這樣大約可以組合了包含7000多個簡體漢字,此外數學符號、羅馬希臘的字母、日文的假名們都編進去了,連在ASCII裏本來就有的數字、標點、字母都統統重新編了兩個字節長的編碼,這就是常說的"全角"字符,而原來在127號以下的那些就叫"半角"字符了。
GBK:最常用的中文碼表。是在GB2312標準基礎上的擴展規範,使用了雙字節編碼方案,共收錄了21003個漢字,完全兼容GB2312標準,同時支持繁體漢字以及日韓漢字等。
GB18030:最新的中文碼表。收錄漢字70244個,采用多字節編碼,每個字可以由1個、2個或4個字節組成。支持中國國內少數民族的文字,同時支持繁體漢字以及日韓漢字等。
Unicode字符集
Unicode編碼系統為表達任意語言的任意字符而設計,是業界的一種標準,也稱為統一碼、標準萬國碼。
它最多使用4個字節的數字來表達每個字母、符號,或者文字。有三種編碼方案,UTF-8、UTF-16和UTF-32。最為常用的UTF-8編碼。
UTF-8編碼,可以用來表示Unicode標準中任何字符,它是電子郵件、網頁及其他存儲或傳送文字的應用中,優先采用的編碼。互聯網工程工作小組(IETF)要求所有互聯網協議都必須支持UTF-8編碼。所以,我們開發Web應用,也要使用UTF-8編碼。它使用一至四個字節為每個字符編碼,編碼規則:
128個US-ASCII字符,只需一個字節編碼。
拉丁文等字符,需要二個字節編碼。
大部分常用字(含中文),使用三個字節編碼。
其他極少使用的Unicode輔助字符,使用四字節編碼。

10.2.2 出現的問題

在IDEA中,使用FileReader 讀取項目中的文本文件。由於IDEA的設置,都是默認的UTF-8編碼,所以沒有任何問題。但是,當讀取Windows系統中創建的文本文件時,由於Windows系統的默認是GBK編碼,就會出現亂碼。 12 1
public class ReaderDemo {
2
    public static void main(String[] args) throws IOException {
3
        FileReader fileReader = new FileReader("E:\\File_GBK.txt");
4
        int read;
5
        while ((read = fileReader.read()) != -1) {
6
            System.out.print((char)read);
7
        }
8
        fileReader.close();
9
    }
10
}
11
輸出結果:
12
???

10.2.3 InputStreamReader類

轉換流java.io.InputStreamReader,是Reader的子類,是從字節流到字符流的橋梁。它讀取字節,並使用指定的字符集將其解碼為字符。它的字符集可以由名稱指定,也可以接受平臺的默認字符集。

GBK : 一個漢字對應2個字節

Utf-8 : 一個漢字對應3個字節

構造方法

InputStreamReader(InputStream in): 創建一個使用默認字符集的字符流。
InputStreamReader(InputStream in, String charsetName): 創建一個指定字符集的字符流。

10.2.4 OutputStreamWriter 類

轉換流java.io.OutputStreamWriter ,是Writer的子類,是從字符流到字節流的橋梁。使用指定的字符集講字符編碼為字節。它的字符集可以由名稱指定,也可以接受平臺的默認字符集。

構造方法

OutputStreamWriter(OutputStream in): 創建一個使用默認字符集的字符流。
OutputStreamWriter(OutputStream in, String charsetName): 創建一個指定字符集的字符流。

轉換流理解圖解

技術分享圖片

10.3 序列化流

10.3.1 概述

Java 提供了一種對象序列化的機制。用一個字節序列可以表示一個對象,該字節序列包含該對象的數據對象的類型對象中存儲的數據等信息。字節序列寫出到文件之後,相當於文件中持久保存了一個對象的信息。

反之,該字節序列還可以從文件中讀取回來,重構對象,對它進行反序列化對象的數據對象的類型`對象中存儲的數據`信息,都可以用來在內存中創建對象。看圖理解序列化: 技術分享圖片

10.3.2 ObjectOutputStream類和ObjectInputStream類
構造方法

  • public ObjectOutputStream(OutputStream out): 創建一個指定OutputStream的ObjectOutputStream。

  • public ObjectInputStream(InputStream in): 創建一個指定InputStream的ObjectInputStream。
Notes:
1.一個對象要想序列化,必須滿足兩個條件:
該類必須實現java.io.Serializable 接口,Serializable 是一個標記接口,不實現此接口的類將不會使任何狀態序列化或反序列化,會拋出NotSerializableException
2.該類的所有屬性必須是可序列化的。如果有一個屬性不需要可序列化的,則該屬性必須註明是瞬態的,使用transient 關鍵字修飾。
8 1
public class Employee implements java.io.Serializable {
2
    public String name;
3
    public String address;
4
    public transient int age; // transient瞬態修飾成員,不會被序列化
5
    public void addressCheck() {
6
      System.out.println("Address  check : " + name + " -- " + address);
7
    }
8
}
寫出對象方法:
public final void writeObject (Object obj)` : 將指定的對象寫出。
public final Object readObject ()` : 讀取一個對象。
27 1
    public static void main(String[] args) throws IOException, ClassNotFoundException {
2
        Student s1 = new Student();
3
        s1.setName("zhangsan");
4
        s1.setAge(14);
5
        s1.setDefault1(9999);
6




7

        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Student"));
8




9

        oos.writeObject(s1);
10




11

        oos.close();
12
        System.out.println("已經被序列化");
13




14

        // 反序列化
15
        FileInputStream fis = new FileInputStream("Student.txt");
16
        ObjectInputStream ois = new ObjectInputStream(fis);
17
        // 讀取一個對象
18
        Student stu  = (Student) ois.readObject();
19
        ois.close();
20
        fis.close();
21




22

        System.out.println("stu = " + stu.getName());
23
        System.out.println("stu = " + stu.getAge());
24
        System.out.println("stu = " + stu.getDefault1());
25
    }
26




27

// 先序列化 再反序列化
反序列化的時候註意:

對於JVM可以反序列化對象,它必須是能夠找到class文件的類。如果找不到該類的class文件,則拋出一個 ClassNotFoundException 異常。

反序列化操作2

另外,當JVM反序列化對象時,能找到class文件,但是class文件在序列化對象之後發生了修改,那麽反序列化操作也會失敗,拋出一個InvalidClassException異常。發生這個異常的原因如下:

該類的序列版本號與從流中讀取的類描述符的版本號不匹配
該類包含未知數據類型
該類沒有可訪問的無參數構造方法

Serializable 接口給需要序列化的類,提供了一個序列版本號。serialVersionUID 該版本號的目的在於驗證序列化的對象和對應類是否版本匹配。

42 1
public class Student implements Serializable {
2
    private String name;
3
    private int age;
4
    private transient int default1;
5




6

    public Student() {
7
    }
8




9

    public Student(String name, int age, int default1) {
10
        this.name = name;
11
        this.age = age;
12
        this.default1 = default1;
13
    }
14




15

    public void addressCheck() {
16
        System.out.println("Address check :" + name + "---" + age);
17
    }
18




19

    public String getName() {
20
        return name;
21
    }
22




23

    public void setName(String name) {
24
        this.name = name;
25
    }
26




27

    public int getAge() {
28
        return age;
29
    }
30




31

    public void setAge(int age) {
32
        this.age = age;
33
    }
34




35

    public int getDefault1() {
36
        return default1;
37
    }
38




39

    public void setDefault1(int default1) {
40
        this.default1 = default1;
41
    }
42
}

10.4 打印流

10.4.1 概述

平時我們在控制臺打印輸出,是調用print方法和println方法完成的,這兩個方法都來自於java.io.PrintStream類,該類能夠方便地打印各種數據類型的值,是一種便捷的輸出方式。

10.4.2 PrintStream類

構造方法

  • `public PrintStream(String fileName) `: 使用指定的文件名創建一個新的打印流。

10.4.3 改變打印流向

12 1
    public static void main(String[] args) throws IOException {
2
// 調用系統的打印流,控制臺直接輸出97
3
        System.out.println(97);
4
      
5
// 創建打印流,指定文件的名稱
6
        PrintStream ps = new PrintStream("ps.txt");
7
      
8
      // 設置系統的打印流流向,輸出到ps.txt
9
        System.setOut(ps);
10
      // 調用系統的打印流,ps.txt中輸出97
11
        System.out.println(97);
12
    }

10.5 屬性集

10.5.1 概述

java.util.Properties 繼承於Hashtable ,來表示一個持久的屬性集。它使用鍵值結構存儲數據,每個鍵及其對應值都是一個字符串。該類也被許多Java類使用,比如獲取系統屬性時,System.getProperties 方法就是返回一個Properties對象。

10.5.2 Properties類

構造方法

  • public Properties() :創建一個空的屬性列表。

  • 基本的存儲方法

    • public Object setProperty(String key, String value) : 保存一對屬性。

    • public String getProperty(String key) :使用此屬性列表中指定的鍵搜索屬性值。

    • public Set<String> stringPropertyNames() :所有鍵的名稱的集合。

與流相關的方法

  • `public void load(InputStream inStream)`: 從字節輸入流中讀取鍵值對。

參數中使用了字節輸入流,通過流對象,可以關聯到某文件上,這樣就能夠加載文本中的數據了。文本數據格式:

18 1
    public static void main(String[] args) throws FileNotFoundException {
2
        // 創建屬性集對象
3
        Properties pro = new Properties();
4
        // 加載文本中信息到屬性集
5
        pro.load(new FileInputStream("read.txt"));
6
        // 遍歷集合並打印
7
        Set<String> strings = pro.stringPropertyNames();
8
        for (String key : strings ) {
9
          System.out.println(key+" -- "+pro.getProperty(key));
10
        }
11
     }
12
結果:
13
filename=a.txt
14
length=209385038
15
location=D:\a.txt
16




17

tips;
18
    文本中的數據,必須是鍵值對形式,可以使用空格、等號、冒號等符號分隔

10.6 Path接口和Files類

10.6.1 概述

  • java.nio.file.Paths :是一個類,該類通過轉換路徑字符串返回一個Path

  • java.nio.file.Path:是一個接口,表示系統相關的文件路徑,用於在文件系統中定位文件的對象,可以替代File類。

  • `java.nio.file.Files`:是一個工具類,包含對文件、目錄進行操作的靜態方法。

10.6.2 便捷的文件操作

x
1
Paths類
2




3

使用Paths,獲取Path對象,代碼演示如下:
4




5

    Path path = Paths.get("D:\\a.txt");
6




7

Files類
8




9

- 刪除文件
10




11

    public static void main(String[] args) throws IOException {
12
      // 獲取Path
13
        Path path = Paths.get("D:\\a.txt");
14
      // 刪除文件
15
        Files.delete(path);
16
    }
17




18

- 文件復制
19




20

    public static void main(String[] args) throws IOException {
21
      // 獲取Path
22
      Path src = Paths.get("D:\\src.txt");
23
      Path target = Paths.get("D:\\target.txt");
24
    
25
        //REPLACE_EXISTING:文件存在,就替換
26
        Files.copy(src, target,StandardCopyOption.REPLACE_EXISTING);
27
    }
28




29

- 逐行讀取文件
30




31

    public static void main(String[] args) throws IOException {
32
      // 獲取path
33
     Path src = Paths.get("D:\\read.txt");
34
      // 創建字符流
35
        BufferedReader reader = Files.newBufferedReader(src,StandardCharsets.UTF_8);
36
      // 讀取字符
37
        String line ;
38
        while((line = reader.readLine()) != null){
39
            System.out.println(line);
40
        }
41
      // 釋放資源
42
        reader.close();
43
    }
44




45





46








 
 




 
 
 
 
 
 
 
 
 
 
 
 
 

<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">



來自為知筆記(Wiz)



10緩沖流、轉換流、序列化流、Files