Java I/O流

weixin_34007291發表於2017-10-03

System.out.print()
還有printf() println()等等一系列的輸出函式是那麼的耀眼,佔據了那麼重要的位置,以至於很多書籍甚至對Logger類隻字不提。

這一段話就像一段咒語,在開始接觸Java的時候我根本就不知道他是什麼意思,只能盲目地寫,最近系統的看了一下,才發現這個“咒語”的水這麼深。

這篇筆記的目錄:

  • System.out/in/err 是什麼玩意兒?
  • System.out 中的過載函式介紹
  • Java糟心的輸入流
  • Java 的輸出流

System.out/in/err 是什麼玩意兒?

System是一個Java中非常重要的類,具體在這裡不做介紹,JavaDoc中只寫了它有三個靜態欄位:

out err in

4714178-48c98c6b8f3b6291.png
image.png

分別對應了這些Stream 不是Steam
out 和 err 都是PrintSteam 是 OutPutSteam 的一個子類,下面會有詳細介紹。

重點談談out 對應的PrintStream

4714178-761e8208c5514aba.png

這些就是我們常用的輸出函式,有C語言風格的printf
還有大量的過載函式等,這些過載函式的引數是可變長度的引數

4714178-b9ff70bf9cd7fc79.png

瞄了一眼原始碼,各種基本型別的輸出都是轉換為String型別在輸出,那麼print(String s)是怎樣做的呢?

4714178-68f3d3339e1e4ac2.png
image.png

這個write是一個私有函式,其中呼叫了BufferedWritter的輸出方write進行緩衝輸出

哦......
至此我們有這兩個結論了

  • √ System.out.print 不是一行咒語,out 是一個PrintStream的例項
  • √ 這個輸出是帶了緩衝的

現在就有了新的疑問,什麼是BufferedWritter PrintStream


我們先來說說Java 中是如何輸入文字到控制檯的:

1.InputStream
還記得System.in嗎?

4714178-83107c18d5eb8b55.png
image.png

這是第一種方式,使用InputStreamReader讀入輸入,BufferedReader緩衝。

Wait !!我有一個問題:
Q:InputStreamReader明明就不是InputStream的子類!
說好的使用InputStream呢!
A: 沒錯!!InputStream 在這裡的用法是System.in,用來獲取控制檯上面的輸入。InputStream自己本身是抽象類,並不能例項化。之所以使用Reader只是方便讀入文字資料而已。

2.使用Scanner

Scanner scanner = new Scanner(System.in);
String temp = scanner.nextLine();

區別
1.Scanner可以解析輸入的文字,使用比如nextInt()
2.Scanner 有一個較小的buffer ,然而BufferedReader的緩衝區要大
3.BufferedReader有同步過
可以看看這篇討論:
Scanner VS BufferedReader

ok,前面都是鋪墊,下面到了最重要的部分!

Java流:

前面說過PrintStream是帶有緩衝的輸出,其實Java的標準輸入輸出都是帶有緩衝的。

4714178-a3e3a6ad7d9afa90.png
image.png

流的概念

我之前其實是非常不理解為什麼要使用“流”這個字來稱呼資料的傳輸的,但是後來就慢慢理解了這樣的一句話:

流是一組有順序的,有起點和終點的位元組集合,
是對資料傳輸的總稱或抽象。即資料在兩裝置間的傳輸稱為流,
流的本質是資料傳輸,
根據資料傳輸特性將流抽象為各種類,方便更直觀的進行資料操作。

可以這樣分類:
1.按輸入輸出分:輸入流/輸出流
2.按處理的資料單位不同:位元組流/字元流
3.按照功能不同:節點流/處理流(過濾流)

可以擺上一張在幾乎每一篇Java I/O流相關的部落格中都使用過的,有一種鎮邪,祭祀意味的圖:

4714178-4422ec58d8182939.png
image.png

我們可以有下面的結論:
Reader Writer含有這樣的欄位的是的字元流;
含有Stream欄位的是位元組流。
有一對特例:
InputStreamReaderOutputStreamWriter(轉換流)


我們按照上面的分類介紹一下好了

就不說輸入和輸出流了,確實很簡單容易看出來。

  • 位元組流

裝置上的很多資料,比如視訊等等都是用位元組處理的,所以,可以說位元組是計算機資料的最小單元;
一次讀入或者讀出是八位二進位制資料。
此外,文字檔案也是資料,一般處理文字會使用字元流處理。

  • 字元流

字元流是基於位元組流讀取,根據碼錶讀取字元
一次讀入或者讀出是16位二進位制

此外在字元流和位元組流中還有介質流

  • 介質流是指從陣列和物件中讀取資料(byte[] char[] StringBuffer)

  • 節點流

節點流:直接和資料來源相連的讀寫 流

4714178-8302e95e048341df.png
image.png

處理流:FilterInputStream或者FilterOutputSteam及其子類。
因為處理流需要有InputStreamOutputStream作為構造器的引數,所以查一下JavaDoc就容易知道。

最後說一下InputStreamReaderOutputStreamWriter
InputStream就是位元組流通向字元流的橋樑。
如果不自己制定的話,就會採用以平臺定義的編碼方式,比如說GBK。

InputStreamReader(InputStream in, Charset cs)

使用方法:

InputStream in = new FileInputStream("xxx");
InputStreamReader reader = new InputStreamReader(in);
char [] temp = new char[1024];
int length = reader.read(temp);
System.out.println(new String(temp,0,length));

Writer的方法使用類似。

public static void streamToReader(InputStream in) throws IOException {
        InputStreamReader isReader = new InputStreamReader(in);
        BufferedReader reader = new BufferedReader(isReader);
        char [] temp = new char[1024];
        int length = reader.read(temp);
        System.out.println(new String(temp));
    }
  public static void writeInFile(File in,File out) throws IOException {
        FileInputStream inputStream = new FileInputStream(in);
        FileOutputStream outputStream = new FileOutputStream(out);
        int i = 0;
        while(i != -1) {
            i = inputStream.read();
            outputStream.write(i);
        }
     
        inputStream.close();
        outputStream.close();
    }
  • 參考內容:《Java 程式設計思想》
  • 很多篇簡書,CSDN,還有其他各大網站上面高手們的部落格

相關文章