溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

JAVA IO體系是怎樣的

發(fā)布時(shí)間:2021-09-28 11:05:18 來(lái)源:億速云 閱讀:128 作者:柒染 欄目:大數(shù)據(jù)

本篇文章給大家分享的是有關(guān)JAVA IO體系是怎樣的,小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說(shuō),跟著小編一起來(lái)看看吧。

  • 基于字節(jié)的IO操作

JAVA IO體系是怎樣的

JAVA IO體系是怎樣的

  • 基于字符的IO操作

JAVA IO體系是怎樣的

JAVA IO體系是怎樣的

從上圖可以看到,整個(gè)Java IO體系都是基于字節(jié)流(InputStream/OutputStream) 和 字符流(Reader/Writer)作為基類,根據(jù)不同的數(shù)據(jù)載體或功能派生出來(lái)的。

----------------------------------------------------------------------------------------------------------------------------------------------------------------

IO常用類

  • 文件流:FileInputStream/FileOutputStream, FileReader/FileWriter

這四個(gè)類是專門操作文件流的,用法高度相似,區(qū)別在于前面兩個(gè)是操作字節(jié)流,后面兩個(gè)是操作字符流。它們都會(huì)直接操作文件流,直接與OS底層交互。因此他們也被稱為節(jié)點(diǎn)流

注意使用這幾個(gè)流的對(duì)象之后,需要關(guān)閉流對(duì)象,因?yàn)閖ava垃圾回收器不會(huì)主動(dòng)回收。不過在Java7之后,可以在 try() 括號(hào)中打開流,最后程序會(huì)自動(dòng)關(guān)閉流對(duì)象,不再需要顯示地close。

下面演示這四個(gè)流對(duì)象的基本用法,

package io;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class TestIO {
    public static void FileInputStreamTest() throws IOException {
        FileInputStream fis = new FileInputStream("tmp2.txt");
        byte[] buf = new byte[1024];
        int hasRead = 0;
        
        //read()返回的是單個(gè)字節(jié)數(shù)據(jù)(字節(jié)數(shù)據(jù)可以直接專程int類型),但是read(buf)返回的是讀取到的字節(jié)數(shù),真正的數(shù)據(jù)保存在buf中
        while ((hasRead = fis.read(buf)) > 0) {
            //每次最多將1024個(gè)字節(jié)轉(zhuǎn)換成字符串,這里tmp2.txt中的字符小于1024,所以一次就讀完了
            //循環(huán)次數(shù) = 文件字符數(shù) 除以 buf長(zhǎng)度
            System.out.println(new String(buf, 0 ,hasRead));
            /*
             * 將字節(jié)強(qiáng)制轉(zhuǎn)換成字符后逐個(gè)輸出,能實(shí)現(xiàn)和上面一樣的效果。但是如果源文件是中文的話可能會(huì)亂碼
             
            for (byte b : buf)    {
                char ch = (char)b;
                if (ch != '\r')
                System.out.print(ch);
            }
            */
        }
        //在finally塊里close更安全
        fis.close();
    }
    
    public static void FileReaderTest() throws IOException {
        
        try (
                // 在try() 中打開的文件, JVM會(huì)自動(dòng)關(guān)閉
                FileReader fr = new FileReader("tmp2.txt")) {
            char[] buf = new char[32];
            int hasRead = 0;
            // 每個(gè)char都占兩個(gè)字節(jié),每個(gè)字符或者漢字都是占2個(gè)字節(jié),因此無(wú)論buf長(zhǎng)度為多少,總是能讀取中文字符長(zhǎng)度的整數(shù)倍,不會(huì)亂碼
            while ((hasRead = fr.read(buf)) > 0) {
                // 如果buf的長(zhǎng)度大于文件每行的長(zhǎng)度,就可以完整輸出每行,否則會(huì)斷行。
                // 循環(huán)次數(shù) = 文件字符數(shù) 除以 buf長(zhǎng)度
                System.out.println(new String(buf, 0, hasRead));
                // 跟上面效果一樣
                // System.out.println(buf);
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    
    public static void FileOutputStreamTest() throws FileNotFoundException, IOException {
        try (    
                //在try()中打開文件會(huì)在結(jié)尾自動(dòng)關(guān)閉
                FileInputStream fis = new FileInputStream("tmp2.txt");
                FileOutputStream fos = new FileOutputStream("tmp3.txt");
                ) {
            byte[] buf = new byte[4];
            int hasRead = 0;
            while ((hasRead = fis.read(buf)) > 0) {
                //每讀取一次就寫一次,讀多少就寫多少
                fos.write(buf, 0, hasRead);
            }
            System.out.println("write success");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public static void FileWriterTest() throws IOException {
        try (FileWriter fw = new FileWriter("tmp4.txt")) {
            fw.write("天王蓋地虎\r\n");
            fw.write("寶塔鎮(zhèn)河妖\r\n");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws IOException {
        //FileInputStreamTest();
        //FileReaderTest();
        //FileOutputStreamTest();
        FileWriterTest();
    }
}
  • 包裝流:PrintStream/PrintWriter/Scanner

PrintStream可以封裝(包裝)直接與文件交互的節(jié)點(diǎn)流對(duì)象OutputStream, 使得編程人員可以忽略設(shè)備底層的差異,進(jìn)行一致的IO操作。因此這種流也稱為處理流或者包裝流。

PrintWriter除了可以包裝字節(jié)流OutputStream之外,還能包裝字符流Writer

Scanner可以包裝鍵盤輸入,方便地將鍵盤輸入的內(nèi)容轉(zhuǎn)換成我們想要的數(shù)據(jù)類型。

  • 字符串流:StringReader/StringWriter

這兩個(gè)操作的是專門操作String字符串的流,其中StringReader能從String中方便地讀取數(shù)據(jù)并保存到char數(shù)組,而StringWriter則將字符串類型的數(shù)據(jù)寫入到StringBuffer中(因?yàn)镾tring不可寫)。

  • 轉(zhuǎn)換流:InputStreamReader/OutputStreamReader

這兩個(gè)類可以將字節(jié)流轉(zhuǎn)換成字符流,被稱為字節(jié)流與字符流之間的橋梁。我們經(jīng)常在讀取鍵盤輸入(System.in)或網(wǎng)絡(luò)通信的時(shí)候,需要使用這兩個(gè)類

  • 緩沖流:BufferedReader/BufferedWriter , BufferedInputStream/BufferedOutputStream

Oracle官方的描述:

Most of the examples we've seen so far use unbuffered I/O. This means each read or write request is handled directly by the underlying OS. This can make a program much less efficient.

Buffered input streams read data from a memory area known as a buffer; the native input API is called only when the buffer is empty. Similarly, buffered output streams write data to a buffer, and the native output API is called only when the buffer is full.

即,

沒有經(jīng)過Buffered處理的IO, 意味著每一次讀和寫的請(qǐng)求都會(huì)由OS底層直接處理,這會(huì)導(dǎo)致非常低效的問題。

經(jīng)過Buffered處理過的輸入流將會(huì)從一個(gè)buffer內(nèi)存區(qū)域讀取數(shù)據(jù),本地API只會(huì)在buffer空了之后才會(huì)被調(diào)用(可能一次調(diào)用會(huì)填充很多數(shù)據(jù)進(jìn)buffer)。

經(jīng)過Buffered處理過的輸出流將會(huì)把數(shù)據(jù)寫入到buffer中,本地API只會(huì)在buffer滿了之后才會(huì)被調(diào)用。

BufferedReader/BufferedWriter可以將字符流(Reader)包裝成緩沖流,這是最常見用的做法。

另外,BufferedReader提供一個(gè)readLine()可以方便地讀取一行,而FileInputStream和FileReader只能讀取一個(gè)字節(jié)或者一個(gè)字符,

因此BufferedReader也被稱為行讀取器

package io;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.PushbackReader;
import java.io.StringReader;
import java.io.StringWriter;

public class TestIO {
    public static void printStream() throws FileNotFoundException, IOException {
        try (
                FileOutputStream fos = new FileOutputStream("tmp.txt");
                PrintStream ps = new PrintStream(fos)) {
            ps.println("普通字符串\n");
            //輸出對(duì)象
            ps.println(new TestIO());
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("輸出完成");
                
    }
    public static void stringNode() throws IOException {
        String str = "天王蓋地虎\n"
                + "寶塔鎮(zhèn)河妖\n";
        char[] buf = new char[32];
        int hasRead = 0;
        //StringReader將以String字符串為節(jié)點(diǎn)讀取數(shù)據(jù)
        try (StringReader sr = new StringReader(str)) {
            while ((hasRead = sr.read(buf)) > 0) {
                System.out.print(new String(buf, 0, hasRead));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        //由于String是一個(gè)不可變類,因此創(chuàng)建StringWriter時(shí),實(shí)際上是以一個(gè)StringBuffer作為輸出節(jié)點(diǎn)
        try (StringWriter sw = new StringWriter()) {
            sw.write("黑夜給了我黑色的眼睛\n");
            sw.write("我卻用它尋找光明\n");
            //toString()返回sw節(jié)點(diǎn)內(nèi)的數(shù)據(jù)
            System.out.println(sw.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public static void keyIn() throws IOException {
        try (
                //InputStreamReader是從byte轉(zhuǎn)成char的橋梁
                InputStreamReader reader = new InputStreamReader(System.in);
                //BufferedReader(Reader in)是char類型輸入的包裝類
                BufferedReader br = new BufferedReader(reader);
                ) {
            String line = null;
            while ((line = br.readLine()) != null) {
                if (line.equals("exit")) {
                    //System.exit(1);
                    break;
                }
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public static void pushback() throws FileNotFoundException, IOException {
        try (PushbackReader pr = new PushbackReader(new FileReader("C:/PROJECT/JavaBasic/PROJECT_JavaBasic/src/io/TestIO.java"),64)) {
            char[] buf = new char[32];
            String lastContent = "";
            int hasRead = 0;
            while ((hasRead = pr.read(buf)) > 0) {
                String content = new String(buf, 0, hasRead);
                int targetIndex = 0;
                if ((targetIndex = (lastContent + content).indexOf("targetIndex = (lastContent + content)")) > 0) {
                    pr.unread((lastContent + content).toCharArray());
                    if (targetIndex > 32) {
                        buf = new char[targetIndex];
                    }
                    pr.read(buf , 0 , targetIndex);
                    System.out.println(new String(buf, 0 , targetIndex));
                    System.exit(0);
                } else {
                    System.out.println(lastContent);
                    lastContent = content;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) throws IOException {
        printStream();
        //stringNode();
        //keyIn();
        //pushback();
    }
}

總結(jié)上面幾種流的應(yīng)用場(chǎng)景:

  • FileInputStream/FileOutputStream  需要逐個(gè)字節(jié)處理原始二進(jìn)制流的時(shí)候使用,效率低下

  • FileReader/FileWriter 需要組個(gè)字符處理的時(shí)候使用

  • StringReader/StringWriter 需要處理字符串的時(shí)候,可以將字符串保存為字符數(shù)組

  • PrintStream/PrintWriter 用來(lái)包裝FileOutputStream 對(duì)象,方便直接將String字符串寫入文件 

  • Scanner 用來(lái)包裝System.in流,很方便地將輸入的String字符串轉(zhuǎn)換成需要的數(shù)據(jù)類型

  • InputStreamReader/OutputStreamReader ,  字節(jié)和字符的轉(zhuǎn)換橋梁,在網(wǎng)絡(luò)通信或者處理鍵盤輸入的時(shí)候用

  • BufferedReader/BufferedWriter , BufferedInputStream/BufferedOutputStream , 緩沖流用來(lái)包裝字節(jié)流后者字符流,提升IO性能,BufferedReader還可以方便地讀取一行,簡(jiǎn)化編程。

以上就是JAVA IO體系是怎樣的,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見到或用到的。希望你能通過這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI