欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java字節(jié)流和字符流總結(jié)IO流!

 更新時間:2021年07月17日 14:35:33   作者:蛋撻學(xué)姐  
下面小編就為大家?guī)硪黄狫ava IO流字節(jié)流和字符流的實例講解。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

從接收輸入值說起

在日常的開發(fā)應(yīng)用中,有時候需要直接接收外部設(shè)備如鍵盤等的輸入值,而對于這種數(shù)據(jù)的接收方式,我們一般有三種方法:字節(jié)流讀取,字符流讀取,Scanner 工具類讀取。

字節(jié)流讀取

直接看一個例子:

public class Demo01SystemIn {
    public static void main(String[] args) throws IOException {
        int a = System.in.read();
        System.out.println(a);
        char c = 'a';
        System.out.println((int) c);
    }
}

運行程序之后,會被 read 方法阻塞,這時候在控制臺輸入一個字符 a,那么上面的程序兩句話都會輸出 97,這個沒問題,因為小寫字母 a 對應(yīng)的就是 97,那么假如我們輸入一個中文會出現(xiàn)什么結(jié)果呢?

把上面示例中的 a 修改為 中,然后運行程序,在控制臺同樣輸入 中,則會得到 228 和 20013,這就說明我們控制臺輸入的 中 并沒有全部讀取,原因就是 read 只能讀取 1 個字節(jié),為了進一步驗證結(jié)論,我們將上面的例子進行改寫:

public class Demo01SystemIn {
    public static void main(String[] args) throws IOException {
        char a = (char) System.in.read();//讀取一個字節(jié)
        System.out.println(a);
        char c = '中';
        System.out.println(c);
    }
}

運行之后得到如下結(jié)果:

可以看到,第一個輸出亂碼了,因為 System.in.read() 一次只能讀取一個字節(jié),而中文在 utf-8 編碼下占用了 3 個字節(jié)。正因為 read 方法一次只能讀取一個字節(jié),所以其范圍只能在 -1~255 之間,-1 表示已經(jīng)讀取到了結(jié)尾。【參考文獻】

那么如果想要完整的讀取中文應(yīng)該怎么辦呢?

字符流讀取

我們先看下面一個例子:

public class Demo01SystemIn {
    public static void main(String[] args) throws IOException {
        InputStreamReader inputStreamReader1 = new InputStreamReader(System.in);
        int b = inputStreamReader1.read();//只能讀一個字符
        System.out.println(b);
        InputStreamReader inputStreamReader2 = new InputStreamReader(System.in);
        char[] chars = new char[2];
        int c = inputStreamReader2.read(chars);//讀入到指定char數(shù)組,返回當(dāng)前讀取到的字符數(shù)
        System.out.println("讀取的字符數(shù)為:" + c);
        System.out.println(chars[0]);
        System.out.println(chars[1]);
    }
}//加入Java開發(fā)交流君樣:756584822一起吹水聊天

運行之后,輸出結(jié)果如下所示:

這個時候我們已經(jīng)能完成的讀取到一個字符了,當(dāng)然,有時候為了優(yōu)化,我們需要使用 BufferedReader 進行進一步的包裝:

BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));

這種方式雖然解決了讀取中文會亂碼問題,但是使用起來也不是很方便,所以一般讀取鍵盤輸入信息我們都會采用 Scnner 來讀取。

Scanner 讀取

Scanner 實際上還是對 System.in 進行了封裝,并提供了一系列方法來讀取不同的字符類型,比如 nextInt,nextFloat,以及 next 等。

public class Demo02Scnner {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextInt()){
            System.out.println(scanner.nextInt());
        }
    }//加入Java開發(fā)交流君樣:756584822一起吹水聊天
}

什么是 IO 流

流是一種抽象概念,它代表了數(shù)據(jù)的無結(jié)構(gòu)化傳輸(摘自百度百科)。IO 流對應(yīng)的就是 InPut 和 Output,也就是輸入和輸出。輸入和輸出這個概念是針對于應(yīng)用程序而言,比如當(dāng)前程序中需要讀取文件中的內(nèi)容,那么這就是輸入,而如果需要將應(yīng)用程序本身的數(shù)據(jù)發(fā)送到其他應(yīng)用,就對應(yīng)了輸出。

字節(jié)流和字符流

根據(jù)流的處理方式又可以將流可以分為兩種類型:字節(jié)流和字符流。

字節(jié)流

字節(jié)流讀取的基本單位為字節(jié),采用的是 ASCII 編碼,通常用來處理二進制數(shù)據(jù),其頂層抽象類為 InputStream 和 OutputStream,比如上面示例中的 System.in 實際上就是獲取到了一個 InputStream 類。

Java 中的流家族非常龐大,提供了非常多的具有不同功能的流,在實際應(yīng)用中我們可以選擇不同的組合達到目的。

字節(jié)輸入流

下圖為字節(jié)輸入流家族關(guān)系示意圖:

從上圖可以看出這些結(jié)構(gòu)非常清晰,首先是一個最頂層的接口,其次就是一些不同功能的基礎(chǔ)流,比如我們最常用的 FileInputStream 就是用來讀取文件的,這其中有一個 FilterInputStream 流,這個流主要是用來擴展基礎(chǔ)流功能,其本身只是簡單的覆蓋了父類 InputStream 中的所有方法,并沒有做什么特殊處理,真正的功能擴展需要依賴于其眾多的子類,比如最常用的 BufferedInputStream 提供了數(shù)據(jù)的緩沖,從而提升讀取流的效率,而 DataInputStream 是可以用來處理二進制數(shù)據(jù)等等。

通過這些眾多不同功能的流來組合,可以靈活的讀取我們需要的數(shù)據(jù)。比如當(dāng)我們需要讀取一個二進制文件,那么就需要使用 DataInputStream,而 DataInputStream 本身不具備直接讀取文件內(nèi)容的功能,所以需要結(jié)合 FileInputStream:

FileInputStream fin = new FileInputStream("E:\\test.txt");
DataInputStream din = new DataInputStream(fin);
System.out.println(din.readInt());

同時,如果我們想要使用緩沖機制,又可以進一步組裝 BufferedInputStream:

FileInputStream fin = new FileInputStream("E:\\test.txt");
DataInputStream din = new DataInputStream(new BufferedInputStream(fin));
System.out.println(din.readInt());

還有一種流比較有意思,那就是 PushbackInputStream,這個流可以將讀出來的數(shù)據(jù)重新推回到流中:

public class Demo03 {
    public static void main(String[] args) throws IOException {
        FileInputStream fin = new FileInputStream("E:\\test.txt");//文檔內(nèi)存儲 abcd
        PushbackInputStream pin = new PushbackInputStream(new BufferedInputStream(fin));
//加入Java開發(fā)交流君樣:756584822一起吹水聊天
        int a = pin.read();//讀取到a
        System.out.println(a);
        if (a != 'b'){
            pin.unread(a);//將 a 推回流中
        }
        System.out.println(pin.read());//再次讀取到 a
        System.out.println(pin.read());//讀取到 b
        System.out.println(pin.read());// 讀取到 c
    }
}

字節(jié)輸出流

下圖為字節(jié)輸出流家族關(guān)系示意圖:

這個結(jié)構(gòu)和輸入流的結(jié)構(gòu)基本類似,同樣的我們也可以通過組合來實現(xiàn)不同的輸出。

比如普通的輸出文件,可以使用 FileOutputStream 流:

FileOutputStream fout = new FileOutputStream("E:\\test2.txt");
fout.write(1);
fout.write(2);

如果`想要輸出二進制格式,那么就可以組合 DataOutputStream 流:

FileOutputStream fout = new FileOutputStream("E:\\test2.txt");
DataOutputStream dout = new DataOutputStream(fout);
dout.write(9);//加入Java開發(fā)交流君樣:756584822一起吹水聊天
dout.write(10);

緩沖流的原理

IO 操作是一個比較耗時的操作,而字節(jié)流的 read 方法一次只能返回一個字節(jié),那么當(dāng)我們需要讀取多個字節(jié)時就會出現(xiàn)每次讀取都要進行一次 IO 操作,而緩沖流內(nèi)部定義了一個大小為 8192 的 byte 數(shù)組,當(dāng)我們使用了緩沖流時,讀取數(shù)據(jù)的時候則會一次性最多讀取 8192 個字節(jié)放到內(nèi)存,然后一個個依次返回,這樣就大大減少了 IO 次數(shù);同樣的,寫數(shù)據(jù)時,緩沖流會將數(shù)據(jù)先寫到內(nèi)存,當(dāng)我們寫完需要寫的數(shù)據(jù)時再一次性刷新到指定位置,如磁盤等。

字符流

字符流讀取的基本單位為字符,采用的是 Unicode 編碼,其 read 方法返回的是一個 Unicode 碼元(0~65535)。

字符流通常用來處理文本數(shù)據(jù),其頂層抽象類為 Reader 和 Write,比如文中最開始的示例中的 InputStreamReader 就是繼承自 Reader 類。

字符輸入流

下圖為字符輸入流家族關(guān)系示意圖:

上圖可以看出,除頂層 Reader 類之外,字符流也提供了一些基本的字符流來處理文本數(shù)據(jù),比如我們需要從文本讀取內(nèi)容:

public class Demo05Reader {
    public static void main(String[] args) throws Exception {
        //字節(jié)流
        FileInputStream fin = new FileInputStream("E:\\test.txt");//文本內(nèi)容為“雙子孤狼”
        System.out.println(fin.read());//372
        //字符流
        //加入Java開發(fā)交流君樣:756584822一起吹水聊天
        InputStreamReader ir = new InputStreamReader(new FileInputStream("E:\\test.txt"));//文本內(nèi)容為“雙子孤狼”
        System.out.println(ir.read());//21452
        char s = '雙';
        System.out.println((int)s);//21452
    }
}

輸出之后可以很明顯看出區(qū)別,字節(jié)流一次讀入一個字節(jié),而字符流一次讀入一個字符。

當(dāng)然,我們也可以采用自由組合的方式來更靈活的進行字符讀取,比如我們結(jié)合 BufferedReader 來讀取一整行數(shù)據(jù):

public class Demo05Reader {
    public static void main(String[] args) throws Exception {
        InputStreamReader ir = new InputStreamReader(new FileInputStream("E:\\test.txt"));//文本內(nèi)容為“雙子孤狼”
        BufferedReader br = new BufferedReader(ir);
        String s;
        while (null != (s = br.readLine())){
            System.out.println(s);//輸出雙子孤狼
        }
    }
}

字符輸出流

下圖為字符輸出流家族關(guān)系示意圖:

文本輸出,我們用的最多的就是 PrintWriter,這個類我想絕大部分朋友都使用過:

public class Demo06Writer {
    public static void main(String[] args) throws Exception{
        PrintWriter printWriter = new PrintWriter("E:\\test3.txt");
        printWriter.write("雙子孤狼");
        printWriter.flush();
    }
}

這里和字節(jié)流的區(qū)別就是寫完之后需要手動調(diào)用 flush 方法,否則數(shù)據(jù)就會丟失,并不會寫到文件中。

為什么字符流需要 flush,而字節(jié)流不需要

字節(jié)流不需要 flush 操作是因為字節(jié)流直接操作的是字節(jié),中途不需要做任何轉(zhuǎn)換,所以直接就可以操作文件,而字符流,說到底,其底層還是字節(jié)流,但是字符流幫我們將字節(jié)轉(zhuǎn)換成了字符,這個轉(zhuǎn)換需要依賴字符表,所以就需要在字符和字節(jié)完成轉(zhuǎn)換之后通過 flush 操作刷到磁盤中。

需要注意的是,字節(jié)輸出流最頂層類 OutputStream 中也提供了 flush 方法,但是它是一個空的方法,如果有子類有需要,也可以實現(xiàn) flush 方法。

RandomAccessFile

RandomAccessFile 是一個隨機訪問文件類,其可以在文件中的任意位置查找或者寫入數(shù)據(jù)。

public class Demo07RandomAccessFile {
    public static void main(String[] args) throws Exception {
        //文檔內(nèi)容為 lonely wolf
        RandomAccessFile inOut = new RandomAccessFile(new File("E:\\test.txt"),"rw");
        System.out.println("當(dāng)前指針在:" + inOut.getFilePointer());//默認在0
        System.out.println((char) inOut.read());//讀到 l
        System.out.println("當(dāng)前指針在:" + inOut.getFilePointer());
        inOut.seek(7L);//指針跳轉(zhuǎn)到7的位置
        System.out.println((char) inOut.read());//讀到 w
        inOut.seek(7);//跳回到 7
        //加入Java開發(fā)交流君樣:756584822一起吹水聊天
        inOut.write(new byte[]{'c','h','i','n','a'});//寫入 china,此時 wolf被覆蓋
        inOut.seek(7);//繼續(xù)跳回到 7
        System.out.println((char) inOut.read());//此時因為 wolf 被 china覆蓋,所以讀到 c
    }
}

根據(jù)上面的示例中的輸出結(jié)果,可以看到 RandomAccessFile 類可以隨機指定指針,并隨機進行讀寫,功能非常強大。

另外需要說明的是,構(gòu)造 RandomAccessFile 時需要傳入一個模式,模式主要有 4 種:

  • r:只讀模式。此時調(diào)用任何 write 相關(guān)方法,會拋出 IOException。
  • rw:讀寫模式。支持讀寫,如果文件不存在,則會創(chuàng)建。
  • rws:讀寫模式。每當(dāng)進行寫操作,會將內(nèi)容或者元數(shù)據(jù)同步刷新到磁盤。
  • rwd:讀寫模式。每當(dāng)進行寫操作時,會將變動的內(nèi)容用同步刷新到磁盤。

總結(jié)

本文主要將 Java 中的 IO 流進行了梳理,通過將其分成字節(jié)流和字符流,以及輸入流和輸出流分別統(tǒng)計,來建立一個對 Java 中 IO 流全局的概念,最后通過一些實例來演示了如何通過不同類型的流來組合實現(xiàn)強大靈活的輸入和輸出,最后,介紹了同時支持輸入和輸出的 RandomAccessFile。

本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • Java 8 Stream.distinct() 列表去重的操作

    Java 8 Stream.distinct() 列表去重的操作

    這篇文章主要介紹了Java 8 Stream.distinct() 列表去重的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • 詳解RocketMQ中的消費者啟動與消費流程分析

    詳解RocketMQ中的消費者啟動與消費流程分析

    本文主要介紹了RocketMQ的消費者啟動流程,結(jié)合官方源碼和示例,一步步講述消費者在啟動和消息消費中的的工作原理及內(nèi)容,并結(jié)合平時業(yè)務(wù)工作中,對我們所熟悉的順序、push/pull模式等進行詳細分析,以及對于消息消費失敗和重投帶來問題去進行分析,需要的朋友可以參考下
    2022-07-07
  • springmvc fastjson 反序列化時間格式化方法(推薦)

    springmvc fastjson 反序列化時間格式化方法(推薦)

    下面小編就為大家?guī)硪黄猻pringmvc fastjson 反序列化時間格式化方法(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • Java中如何判斷中文字符串長度

    Java中如何判斷中文字符串長度

    這篇文章主要介紹了Java中如何判斷中文字符串長度問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • 詳解Java內(nèi)存泄露的示例代碼

    詳解Java內(nèi)存泄露的示例代碼

    這篇文章通過一個Demo來簡要介紹下ThreadLocal和ClassLoader導(dǎo)致內(nèi)存泄露最終OutOfMemory的場景。下面通過示例代碼給大家分享Java內(nèi)存泄露的相關(guān)知識,感興趣的朋友一起看看吧
    2017-12-12
  • java集合map取key使用示例 java遍歷map

    java集合map取key使用示例 java遍歷map

    這篇文章主要介紹了java集合map取key使用示例,需要的朋友可以參考下
    2014-02-02
  • 深入C++ typedef的用法總結(jié)(必看)

    深入C++ typedef的用法總結(jié)(必看)

    本篇文章是對C++中typedef的用法進行了詳細的總結(jié)分析,需要的朋友參考下
    2013-05-05
  • knife4j?整合?springboot的過程詳解

    knife4j?整合?springboot的過程詳解

    這篇文章主要介紹了knife4j整合springboot的過程,本次整合springboot版本為2.3.12,本文通過圖文實例相結(jié)合給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-09-09
  • Java連接mysql數(shù)據(jù)庫以及mysql驅(qū)動jar包下載和使用方法

    Java連接mysql數(shù)據(jù)庫以及mysql驅(qū)動jar包下載和使用方法

    這篇文章主要給大家介紹了關(guān)于Java連接mysql數(shù)據(jù)庫以及mysql驅(qū)動jar包下載和使用方法,MySQL是一款常用的關(guān)系型數(shù)據(jù)庫,它的JDBC驅(qū)動程序使得我們可以通過Java程序連接MySQL數(shù)據(jù)庫進行數(shù)據(jù)操作,需要的朋友可以參考下
    2023-11-11
  • java 開發(fā)使用字符串和數(shù)字的性能分析

    java 開發(fā)使用字符串和數(shù)字的性能分析

    這篇文章主要介紹了java 開發(fā)使用字符串和數(shù)字的性能分析的相關(guān)資料,需要的朋友可以參考下
    2017-07-07

最新評論