【Java】基本I/O的學習總結


計算機I/O

理解IO先要知道計算機對數據的輸入輸出是怎么處理的,下面一張圖可以大致理解:

可以看出所謂輸入是外部數據向CPU輸入,而輸出是CPU將數據輸出到我們可見的地方,例如文件、屏幕等。而計算機通常是通過流來傳遞數據。

Java I/O

Java中的IO包中的類可以處理不同類型的流,例如:字節流(byte[])、字符流(character)、文件流、對象流等。
java.io中的抽象類:

  • 處理字節流的抽象類:InputStream和OutputStream
  • 處理過濾流的抽象類:FilterOutputStream和FilterInputStream
  • 處理字符流的抽象類:Reader和Writer
  • 處理壓縮流的抽象類:InflaterInputStream和DeflaterOutputStream
    它們之間的關系如下:

字符流

輸入流Reader

基本的字符輸入流的類結構如下,每個類的作用從類名大致可以猜出:

這里想強調的是出現的設計模式————裝飾器模式:

例如其中BufferedReader是對Reader接口的其他子類的一個裝飾器,封裝了其他Reader接口實現類,提供更方便的方法調用。
BufferedReader的構造器如下,初始化時需要傳入一個對Reader接口的實現類的對象:

public BufferedReader(Reader in){}

實例代碼,讀取指定路徑的文件內容並輸出:

public class ReaderTest {
    public static String read(String path) throws IOException {
        //裝飾器模式,BufferedReader包裝了FileReader
        BufferedReader reader = new BufferedReader(new FileReader(path));
        String s;
        StringBuilder sb = new StringBuilder();
        while ((s = reader.readLine()) != null) {
            sb.append(s + "\n");
        }
        reader.close();
        return sb.toString();
    }

    public static void main(String[] args) throws IOException {
        System.out.println(read("D:/test.txt"));
    }
}

可以看出BufferedReader封裝了FileReader來提供更方便的文件輸入功能。

輸出流Writer

類比輸出流,輸出流很容易理解,類關系如下:

同樣也用到了裝飾器模式,下面直接用代碼來說明問題,這段代碼目的是將in.txt的內容寫到out.txt中:

public class WriterTest {
    public static void main(String[] args) throws IOException{
        String inFile = "D:/in.txt";
        String outFile = "D:/out.txt";
        BufferedReader in = new BufferedReader(new StringReader(ReaderTest.read(inFile)));
        PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(outFile)));
        String s;
        int line = 1;
        while ((s = in.readLine()) != null) {
            out.println(line++ + ":" + s);
        }
        in.close();
        out.close();
        System.out.println(ReaderTest.read(outFile));
    }
}

我們可以看出BufferedReader封裝了StringReader,BufferedWriter封裝了FileWriter。

字符流就說這么多吧,具體的類用的時候再去了解也不遲。

字節流

輸入流InputStream

InputStream是以字節流來讀取文件的,如果文件是圖片或二進制等格式,則不能以字符流來讀,需要InputStream來讀取。

InputStream的子類關系如下圖:

值得注意的是,字節流也可以轉換成字節流,利用的是InputStreamReader類,該類封裝了InputStream。下面的實例代碼通過兩種不同的方式來讀取文件內容。其中readByStream是通過字節流,而readByReader是字符流。

public class InputStreamTest {
    public static void readByStream(String path) {
        File f = new File(path);
        try {
            InputStream in = new FileInputStream(f);
            int b;
            while ((b=in.read()) != -1) {
                char c = (char)b;
                System.out.printf("%c", c);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void readByReader(String path) {
        File f = new File(path);
        try {
            InputStream in = new FileInputStream(f);
            BufferedReader reader = new BufferedReader(new InputStreamReader(in, "utf-8"));
            String string;
            StringBuilder sb = new StringBuilder();
            while ((string = reader.readLine()) != null) {
                sb.append(string);
            }
            System.out.println(sb.toString());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        String path = "D:/test.txt";
        readByReader(path);
        readByStream(path);
    }
}

另外,值得注意的是,如果要讀取中文,建議使用字符流,因為一個漢字占兩個字節,而InputStream每次只會讀取一個字節,因此會亂碼。而InputStreamReader有一個構造函數可以設置文件編碼,如上述代碼中的new InputStreamReader(in, "utf-8")指定了文件編碼問utf-8,因此可以很好的解決中文亂碼問題。

輸出流OutputStream

輸出流OutputStream的作用類比於Writer,也非常容易理解,即通過字節流來把數據輸出到文件、磁盤等設備中。關系如下圖。

同InputStream一樣,也有一個OutputStreamWriter包裝了OutputStream,代碼很簡單我就不舉例了。

RandomAccessFile 隨機存取

上面這兩大類IO,雖然結構清晰,但是多少還是復雜了點,於是乎,Java封裝了一個文件隨機存取類————RandomAccessFile。

RandomAccessFile實現了兩個接口,DataInput和DataOutput,因此它同時擁有讀和寫兩個功能,方便了我們的使用。使用時需要指定打開文件的模式,可以是“r”只讀,“rw”讀寫等。下面是實例代碼:

public class RandomAccessTest {
    public static void main(String[] args) {
        String filePath = "D:" + File.separator + "test.txt";
        File f = new File(filePath);
        try {
            RandomAccessFile write = new RandomAccessFile(f, "rw");
            String str = "abc, hello, randomAccess!";
            //把byte[]中的字節寫入文件
            write.write(str.getBytes());
            System.out.println("寫入文件完成...");

            RandomAccessFile read = new RandomAccessFile(f, "rw");
            String strRead;
            StringBuilder sb = new StringBuilder();
            while ((strRead = read.readLine()) != null) {
                sb.append(strRead);
            }
            System.out.println("讀取文件內容:" + sb.toString());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}


免責聲明!

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



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