1. 程式人生 > >21.Java語言緩衝流、轉換流、序列化反序列化、更改列印流

21.Java語言緩衝流、轉換流、序列化反序列化、更改列印流

緩衝流

緩衝流的基本原理,是在建立流物件時,會建立一個內建的預設大小的(8k)緩衝區陣列,通過緩衝區讀寫,減少系統IO次數,從而提高讀寫的效率。

1.位元組緩衝流:

       1).輸出流:OutputStream

              |--FileOutputStream(基本流)

              |--FilterOutputStream

                     |--BufferedOutputStream(緩衝流)

       2).輸入流:InputStream

              |--FileInputStream(基本流)

              |--FilterInputStream

                     |--BufferedInputStream(緩衝流)

       3).構造方法:

BufferedInputStream(InputStream in) 建立一個 BufferedInputStream物件,引數是一個輸入流。InputStream是抽象

類,可以用子類物件

BufferedInputStream(Outputstream out) 建立一個 BufferedInputStream物件,引數是一個輸出流。Outputstream是抽

象類,可以用子類物件

4).程式碼示例:

BufferedInputStream bin = new BufferedInputStream(new FileInputStream("demo.txt"));

BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream("demo.txt"));

2.字元緩衝流:

       1).輸出流:Writer

              |--OutputStreamWriter(轉換流)

                     |--FileWriter(基本流)

              |--BufferedWriter(緩衝流)

              (特有方法:newLine():輸出一個換行符)

       2).輸入流:Reader

              |--InputStreamReader(轉換流)

                     |--FileReader(基本流)

              |--BufferedReader(緩衝流)

               (特有方法:readLine():讀取一行資料)轉換流

       3).構造方法:

       BufferedReader(Reader in) 建立使用預設大小的輸入緩衝區的 緩衝字元輸入流。

       BufferedWriter(Writer out) 建立使用預設大小的輸出緩衝區的緩衝字元輸出流。 

       4).程式碼示例:

BufferedReader bin = new BufferedReader(new FileReader("demo.txt"));

BufferedWriter bout = new BufferedWriter(new FileWriter("demo.txt"));

3.緩衝流的使用_案例_文字排序:

public static void main(String[] args) throws IOException {

    //建立輸入輸出的緩衝流
    BufferedReader bin = new BufferedReader(new FileReader("sort.txt"));
    BufferedWriter bout = new BufferedWriter(new                
                                                 FileWriter("sort_allright.txt"));

    //Map存放序號和對應的句子
    Map<Integer,String> stringMap = new LinkedHashMap<>();

    //用緩衝流的特有方法,一次讀寫一行
    String s = null ;
    while ((s = bin.readLine()) != null) {
        //分割字串
        String[] arr = s.split("\\.");
        stringMap.put(Integer.parseInt(arr[0]), arr[1]);
    }

    //按照序號遍歷Map中的內容並寫出
    for (int i = 1; i < stringMap.size(); i++) {
        bout.write(i + "." + stringMap.get(i));
        bout.newLine();
    }

    //關閉資源
    bin.close();
    bout.close();
}

轉換流

1.字元編碼和字符集:

字元編碼:

就是一套自然語言的字元與二進位制數之間的對應規則。

計算機是以二進位制儲存,按照某種規則,將字元儲存到計算機中,稱為編碼

將儲存在計算機中的二進位制數,按照某種規則解析顯示出來,稱為解碼

字符集: 

常見的字符集(編碼表):記錄了字元和數字的對映關係。當計算機儲存“字元”時,實際儲存的是這個字元對應的數字的二進位制。

       1.ASCII碼錶:最早的碼錶。記錄了128個字元,每個字元使用1個位元組表示。

       2.中文的碼錶(GBxxxx)

              1).GB2312:早期的碼錶,裡面一共記錄了7000多個漢字;現在已經不使用了。

              2).GBK : 目前使用的碼錶。裡面一共記錄了2萬多個漢字,每個漢字使用2個位元組表示;

              3).GB18030 : 未來要使用的碼錶。7萬多漢字。每個漢字使用1,2,3個位元組表示;

     3.UTF-8碼錶:國際碼錶。有中文;字符采用1,2,3,4位元組表示。每個中文使用:3個位元組表示;

     4.Unicode碼錶:國際碼錶,有中文(3,4千),每個字元使用2個位元組表示。Java就是支援Unicode碼錶的。

              5.ISO-8859-1碼錶:沒有中文。

編碼引出的問題:

       亂碼—解碼與編碼不一致

       例如:Windows中文系統中就是使用的GBK的編碼,在IDEA中預設的字符集是UTF-8,兩種編碼中漢字佔用的位元組數不同,(UTF-8佔用三個位元組)讀取時就會出現亂碼          解決:讀取時將編碼轉換成一致

2.轉換輸出流和轉換輸入流:

       1).轉換輸出流:

              構造方法:

              OutputStreamWriter(OutputStream in) : 建立一個用預設字符集的字元流。

OutputStreamWriter(OutputStream in, String charsetName) : 建立一個指定字符集的字元流。

public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
    OutputStreamWriter out1 = new OutputStreamWriter(new FileOutputStream("demo.txt"));
    OutputStreamWriter out2 = new OutputStreamWriter(new FileOutputStream("demo.txt"),"GBK");
}

2).轉換輸入流:

構造方法:

InputStreamReader(InputStream in) : 建立一個使用預設字符集的字元流。

InputStreamReader(InputStream in, String charsetName) : 建立一個指定字符集的字元流。

public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
    InputStreamReader in1 = new InputStreamReader(new FileInputStream("demo.txt"));
    InputStreamReader in2 = new InputStreamReader(new FileInputStream("demo.txt"),"GBk");
}

3.轉換輸入輸出流使用:

IDEA預設的字符集是UTF-8,Windows預設的是GBK,為了避免亂碼,使用GBK讀取文件,然後用UTF-8輸出

public static void main(String[] args) throws IOException {

    //建立指定字符集轉換輸出輸入流,

    InputStreamReader in = new InputStreamReader(
                            new FileInputStream("demo.txt"),"GBK");
    OutputStreamWriter out = new OutputStreamWriter(
                            new FileOutputStream("demo_copy.txt"),"UTF-8");

    //按照字元讀取
    int b = 0;
    while ((b = in.read()) != -1) {
        out.write(b);
    }
    out.close();
    in.close();
}

如果讀取的輸出的編碼不一致就會亂碼

序列化流

序列化:

指將一個“物件連同屬性值”一起儲存在一個檔案中,或者通過網路傳輸,這個過程叫:序列化。

反序列化;

指將之前序列化的物件,再次讀取到程式中,並在記憶體中建立物件。

1.序列化流ObjectOutputStream類;

       構造方法:

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

注意:被序列化的物件必須實現:java.io.Serializable(介面)

         此介面無任何抽象方法,這種介面叫:標記介面,表示開啟了某些功能。

public static void main(String[] args) throws IOException {
    ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("demo_Student.txt"));
    out.writeObject(new Student(1,"張三","男",23));
    out.close();
}

2.反序列化ObjectInputStream類:

       構造方法:

       public ObjectInputStream(InputStream in) : 建立一個指定InputStream的ObjectInputStream。

       注意:接收的Student必須是之前“序列化時”的那個包下的Student型別,不能是其它包下的,否則執行時異常。它必須是能夠找到class檔案的類

public static void main(String[] args) throws IOException, ClassNotFoundException {

    ObjectInputStream in = new ObjectInputStream(new FileInputStream("demo_Student.txt"));

    //返回Object型別
    Student stu = (Student) in.readObject();
    System.out.println(stu);
    in.close();
}

3.版本號:

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

例如:private static final long serialVersionUID = 2;

如果沒有給定序列號,如果修改了序列化的類,再次反序列化的時候(沒有再次序列化)就會拋異常,因為序列號不一樣了,如果給定了序列號,則不會拋異常

4.禁止屬性被序列化transient關鍵字

       用transient關鍵字修飾屬性,在序列化時該甦醒不會被序列化

當一個屬性被transient修飾,反序列化出來的值時屬性的預設值

1       張三       男       0//年齡屬性被禁止序列化,輸出為0

5.序列化的使用_序列化集合:

public static void main(String[] args) throws IOException, ClassNotFoundException {

    //建立序列化的集合並初始化資料
    ArrayList<Student> stuList = new ArrayList<>();
    stuList.add(new Student(1,"張三","男",19));
    stuList.add(new Student(2,"張四","女",20));
    stuList.add(new Student(3,"張五","男",21));
    stuList.add(new Student(4,"張六","女",22));

    //建立序列化輸出流和反序列化輸入流
    ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("demo_xuliehuajihe.txt"));
    ObjectInputStream in = new ObjectInputStream(new FileInputStream("demo_xuliehuajihe.txt"));

    //序列化集合
    out.writeObject(stuList);

    //關閉資源
    out.close();

    //反序列化集合,並接受返回的集合
    ArrayList<Student> studentList = (ArrayList<Student>) in.readObject();

    //遍歷輸出反序列化返回的資料
    for (Student student : studentList) {
        System.out.println(student);
    }
    in.close();

}

列印流

1.位元組列印流PrintStream類

       構造方法:

       public PrintStream(String fileName) 使用指定的檔名建立一個新的列印流。

2.改變列印流的方向:

System.out.println():向控制檯輸出資料,System.out就是:PrintStream型別;預設被指向:控制檯,想改變列印的方向,改變這個out就行

注意:

       Out是System類的一個成員屬性,所以可以用get/set方法訪問

輸出方法和控制檯一樣

使用示例:

public static void main(String[] args) throws FileNotFoundException {
    PrintStream ps = new PrintStream("demo.txt");
    System.setOut(ps);
    System.out.println("呵呵");
}