數據讀寫API——IO流


1.Java 中的IO的作用

IO指的是Input和Output,主要目的是實現數據在存儲介質之間的傳輸。【流:數據流,類比與水流的流動】


2.IO分類

1566628426255

按照操作單元來划分,可以分為字節流和字符流。


3.字節流和字符流的區別


字節流顧名思義操作的數據單元是1個字節,也就是8位;

那么問題來了,一個中文字符用GBK編碼占用兩個字節,用UTF-8占用三個字符。

字節流在傳輸有中文字符的數據時會產生編碼錯誤。

而字符流可操作2個字節,也就是16位。那么在GBK的編碼下,支持中文數據傳輸。


總結如下

  • 字節流一次讀取一個字節,字符流兩個
  • 字節流可以處理所有類型數據,字符流只能處理字符類數據

4.字符編碼的前世今生

ASCII 碼

計算機內部,所有信息最終都是一個二進制值。每一個二進制位(bit)有01兩種狀態,因此八個二進制位就可以組合出256種狀態,這被稱為一個字節(byte)。

也就是說,一個字節一共可以用來表示256種不同的狀態,每一個狀態對應一個符號,就是256個符號,從0000000011111111

上個世紀60年代,美國制定了一套字符編碼,對英語字符與二進制位之間的關系,做了統一規定。這被稱為 ASCII 碼,一直沿用至今。

【ASCII 碼==英文字符和二進制之間的映射關系】


Unicode

世界上存在着多種編碼方式,同一個二進制數字可以被解釋成不同的符號。因此,要想打開一個文本文件,就必須知道它的編碼方式,否則用錯誤的編碼方式解讀,就會出現亂碼。電子郵件常常出現亂碼就是因為發信人和收信人使用的編碼方式不一樣。

可以想象,如果有一種編碼,將世界上所有的符號都納入其中。每一個符號都給予一個獨一無二的編碼,那么亂碼問題就會消失。這就是 Unicode,就像它的名字都表示的,這是一種所有符號的編碼。

Unicode 當然是一個很大的集合,現在的規模可以容納100多萬個符號。每個符號的編碼都不一樣,比如,U+0639表示阿拉伯字母AinU+0041表示英語的大寫字母AU+4E25表示漢字。具體的符號對應表,可以查詢unicode.org,或者專門的漢字對應表

1566632727189

Unicode 的問題

Unicode雖然實現了編碼的一統,但Unicode 只是一個符號集,它只規定了符號的二進制代碼,卻沒有規定這個二進制代碼應該如何存儲。

比如,漢字的 Unicode 是十六進制數4E25,轉換成二進制數足足有15位(100111000100101),也就是說,這個符號的表示至少需要2個字節。表示其他更大的符號,可能需要3個字節或者4個字節,甚至更多。

這里就有兩個嚴重的問題,第一個問題是,如何才能區別 Unicode 和 ASCII ?計算機怎么知道三個字節表示一個符號,而不是分別表示三個符號呢?第二個問題是,我們已經知道,英文字母只用一個字節表示就夠了,如果 Unicode 統一規定,每個符號用三個或四個字節表示,那么每個英文字母前都必然有二到三個字節是0,這對於存儲來說是極大的浪費,文本文件的大小會因此大出二三倍,這是無法接受的。

它們造成的結果是:

1)出現了 Unicode 的多種存儲方式,也就是說有許多種不同的二進制格式,可以用來表示 Unicode。

2)Unicode 在很長一段時間內無法推廣,直到互聯網的出現。

UTF-8

互聯網的普及,強烈要求出現一種統一的編碼方式。UTF-8 就是在互聯網上使用最廣的一種 Unicode 的實現方式。其他實現方式還包括 UTF-16(字符用兩個字節或四個字節表示)和 UTF-32(字符用四個字節表示),不過在互聯網上基本不用。

這里的關系是,UTF-8 是 Unicode 的實現方式之一。

UTF-8 最大的一個特點,就是它是一種變長的編碼方式。它可以使用1~4個字節表示一個符號,根據不同的符號而變化字節長度。


5.節點流,處理流

節點流:直接從數據源或目的地讀寫數據

處理流:不直接連接到數據源或目的地,而是“連接”在已存 在的流(節點流或處理流)之上,通過對數據的處理為程序提 供更為強大的讀寫功能。



常用流

InputStream/Reader:向外邊讀數據

OutpusStream/Writer:向外邊寫數據


節點流(文件流)

import java.io.*;

public class Main {

    public static void main(String args[]) throws IOException
    {
        /**
         * 讀取文件
         * 1.建立一個流對象,將已存在的一個文件加載進流。
         *  FileReader fr = new FileReader(new File(“Test.txt”));
         * 2.創建一個臨時存放數據的數組。
         *  char[] ch = new char[1024];
         * 3.調用流對象的讀取方法將流中的數據讀入到數組中。
         *  fr.read(ch);
         * 4. 關閉資源。
         *  fr.close();
         */

        FileReader fr = null;

            fr = new FileReader(new File("c:\\file.txt"));
            char[] buf = new char[1024];
            int len;
            while ((len = fr.read(buf)) != -1)
            {
                System.out.print(new String(buf, 0, len));
            }
            fr.close();


        /**
         * 寫入文件
         * 1.創建流對象,建立數據存放文件
         *  FileWriter fw = new FileWriter(new File(“Test.txt”));
         * 2.調用流對象的寫入方法,將數據寫入流
         *  fw.write(“atguigu-songhongkang”);
         * 3.關閉流資源,並將流中的數據清空到文件中。
         *  fw.close();
         */

        FileWriter fw = new FileWriter(new File("d:\\filewriter.txt"));
            fw.write("9999999999999");

            fw.close();


        /**
         * 在寫入一個文件時,如果使用構造器FileOutputStream(file),則目錄下有同名文
         * 件將被覆蓋。
         *  如果使用構造器FileOutputStream(file,true),則目錄下的同名文件不會被覆蓋,
         * 在文件內容末尾追加內容。
         */

    }
}

緩沖流(一種處理流)


為了提高數據讀寫的速度,Java API提供了帶緩沖功能的流類,在使用這些流類 時,會創建一個內部緩沖區數組,缺省使用8192個字節(8Kb)的緩沖區。


緩沖流要“套接”在相應的節點流之上,根據數據操作單位可以把緩沖流分為:

BufferedInputStream BufferedOutputStream

BufferedReader BufferedWriter


只要關閉最外層流即可,關閉最外層流也 會相應關閉內層節點流。


flush()方法的使用:手動將buffer中內容寫入文件。

import java.io.*;

public class Main {

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


            BufferedReader br =  new BufferedReader(new FileReader("d:\\br.txt"));
            BufferedWriter bw =  new BufferedWriter(new FileWriter("d:\\bw.txt"));

            String str;
            while ((str = br.readLine()) != null) { // 一次讀取字符文本文件的一行字符
                System.out.println(str);
                bw.write(str); // 一次寫入一行字符串
                bw.newLine(); // 寫入行分隔符
            }
            bw.flush(); // 刷新緩沖區

        br.close();
        bw.close();
    }
}

轉換流

轉換流提供了在字節流和字符流之間的轉換

Java API提供了兩個轉換流:

InputStreamReader:將InputStream轉換為Reader

OutputStreamWriter:將Writer轉換為OutputStream

  • 字節流中的數據都是字符時,轉成字符流操作更高效。
  • 很多時候我們使用轉換流來處理文件亂碼問題。實現編碼和 解碼的功能。
import java.io.*;

public class Main {

    public static void main(String args[]) throws IOException
    {
        /**
         * 將old.txt中的文件讀出寫入到new.txt里
         */


        FileInputStream fis = new FileInputStream("d:\\old.txt");
        FileOutputStream fos = new FileOutputStream("d:\\new.txt");

        InputStreamReader isr = new InputStreamReader(fis, "GBK");
        OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");

        BufferedReader br = new BufferedReader(isr);
        BufferedWriter bw = new BufferedWriter(osw);

        String str = null;
        while ((str = br.readLine()) != null) {
            bw.write(str);
            bw.newLine();
            bw.flush();
        }
        bw.close();
        br.close();
    }
}

1566638564295


參考資料:

字符編碼筆記:ASCII,Unicode 和 UTF-8https://link.zhihu.com/?target=http%3A//www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM