Scanner, BufferedReader, InputStreamReader 與ACM模式輸入

Scanner, BufferedReader, InputStreamReader 與ACM模式輸入

Scanner, BufferedReader, InputStreamReader 與ACM模式輸入

1. Scanner,BufferedReader,InputStreamReader 簡介與對比

java.util.Scanner 類實現了Iterator<String> 和 Closeable介面;可以通過傳入 System.in 從控制台讀取輸入,也可以通過傳入一個File 對象從文件中讀取輸入,還可以通過傳入字元串對象進行讀取;

Scanner 類可以讀取並轉換基本類型的值和字元串;Scanner 使用分隔符 (delimiter pattern) 將其輸入進行分割成標記 (token),默認的分隔符為空格;可以通過調用 useDelimiter() 方法並傳入一個正則表達式字元串來修改分隔符;

java.io.BufferedReader 類繼承自 Reader 類;讀取character-input stream;

java.io.InputStreamReader 類繼承自 Reader類;InputStreamReader類讀取位元組 (byte) 並將其解碼成字元 (character) ;即:將位元組流轉換為字元流;

解碼所使用的字符集可以在實例化對象時通過字元串形式或者 Charset對象傳入,如果不傳入則默認使用系統默認的字符集;

建議將InputStreamReader對象包裝成BufferedReader對象再使用;

Scanner類和BufferedReader類的區別

Scanner 類和BufferedReader 類的區別便是:Scanner類是讀取並轉換輸入流的,而BufferedReader類是直接讀取輸入流,並不做轉換;由此BufferedReader類讀取的速度要比Scanner類讀取的速度快;由於BufferedReader類讀取輸入流不進行轉換,Scanner類也可以通過一個BufferedReader對象來實例化;

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
Scanner fromBufferedScanner = new Scanner(br);

Scanner類的默認快取大小為 1024,BufferedReader類的默認快取大小為 8192;

使用場景建議

如果需要轉換輸入的內容那麼使用Scanner類;

如果需要一行一行地讀取那麼使用BufferedReader類;

2. 詳解Scanner 類

Scanner 類的輸入入方法工作流程

一個標記讀取方法首先跳過任意分隔符,然後讀取一個以分隔符結束的標記;然後針對使用的方法將標記進行轉換,(除了 next() 方法不進行轉換)如果標記和期望的類型不匹配,那麼就會拋出一個運行異常 InputMismatchException 。

基於標記的讀取方法不能讀取標記後面的分隔符。如果在基於標記的讀取方法之後調用nextLine 方法,該方法讀取從這個分隔符開始,到這行的分隔符結束的字元。這個行分隔符也會被讀取,但不會是nextLine 方法返回的字元串的部分。

注意:不建議在一個基於標記的輸入之後使用一個基於行的輸入,後者往往會得到一個空字元串

java.util.Scanner

Name Tags
+ Scanner(source : File) 創建一個Scanner,從指定的文件中產生掃描的值
+ Scanner(source : String) 創建一個Scanner,從指定的字元串中產生掃描的值
+ close() 關閉Scanner
+ hasNext() : boolean 如果Scanner還有更多數據可以讀取,返回true
+ next() : String 從Scanner 中讀取下一個標記作為字元串返回
+ nextLine() : String 從Scanner 中讀取一行,以換行結束
+ nextByte() : byte 從Scanner 中讀取下一個標記作為byte值返回
+ nextShort() : short 從Scanner 中讀取下一個標記作為short值返回
+ nextInt() : int 從Scanner 中讀取下一個標記作為int值返回
+ nextLong() : long 從Scanner 中讀取下一個標記作為long值返回
+ nextFloat() : float 從Scanner 中讀取下一個標記作為float值返回
+ nextDouble() : double 從Scanner 中讀取下一個標記作為double值返回
+ useDelimiter( pattern : String) : Scanner 設置Scanner 的分隔符,並返回Scanner
public class ScannerDemo {
    public static void main(String[] args) {
        // 從控制台輸入 hello 1 2.33
        Scanner fromConsole = new Scanner(System.in);
        String s = fromConsole.next();
        int a = fromConsole.nextInt();
        double b = fromConsole.nextDouble();
        System.out.println(s + " " + a + " " + b);
        fromConsole.close();
    // 讀取字元串
    String input = &quot;hello fish 1 fish 2.33 fish&quot;;
    Scanner fromString = new Scanner(input).useDelimiter(&quot;\\s*fish\\s*&quot;);
    String s2 = fromString.next();
    int a2 = fromString.nextInt();
    double b2 = fromString.nextDouble();
    System.out.println(s2 + &quot; &quot; + a2 + &quot; &quot; + b2);
    fromString.close();
}

}

3. 詳解BufferedReader 類

BufferedReader 類使用中必須要使用try – catch模組或者在方法頭聲明 throws IOException;

常用 readLine() 方法,讀取後可以調用字元串的split方法進行分割再進行後續的操作。

java.io.BufferedReader

Name Tags
+ BufferedReader (in : Reader, sz : int) 創建一個指定輸入快取大小為 sz 的輸入流實例
+ BufferedReader (in : Reader) 創建一個默認輸入快取大小的輸入流實例
+ read() : int 讀取一個字元並返回其對應的值,0~65535之間,如果是在輸入流末尾,那麼返回-1,如果輸入不合法,拋出IOException
+ read(cbuf : char[], off : int, len : int ) : int 將字元輸入流讀取到給定的字元數組中,返回讀取的字元數量,如果到達輸入流的末尾,則返回-1
+ readLine() : String 讀取一行輸入,該行應當以”\n” 或者 “\r” 或者 “\r\n” 作為結束,返回的字元串不包含用作結尾的字元
+ skip( n : long) : long 跳過指定長度的字元輸入,返回實際跳過的字元數量
+ ready() : boolean 如果輸入流快取不為空,則說明buffered character stream已經準備好,返回true;否則返回false
+ markSupported() : boolean 如果該輸入流支援 mark方法,返回true;
+ mark( readAheadLimit : int) : void 標記輸入流的當前位置,如果再調用reset() 方法,那麼將返回該位置
+ reset() : void 返回最近 mark的位置
+ close() : void 關閉輸入流
+ lines() : Stream<String> 返回一個字元串Stream,該Stream由BufferedReader讀取的每行組成
public class BufferedReaderDemo {
    public static void main(String[] args) throws IOException {
        // 從控制台輸入 hello 回車 2.33 回車 2 回車
        InputStreamReader ir = new InputStreamReader(System.in);
        BufferedReader br = new BufferedReader(ir);
        String line1 = br.readLine();
        String line2 = br.readLine();
        String line3 = br.readLine();
        double b = Double.parseDouble(line2);
        int c = Integer.parseInt(line3);
        System.out.println(line1 + " " + b + " " + c);
    }
}

4. 詳解InputStreamReader 類

用於讀取數據時,同樣需要包含在try catch模組中,或者在方法頭聲明 throws IOException

java.io.InputStreamReader

Name Tags
+ InputStreamReader ( in : InputStream) 使用默認字符集創建輸入流
+ InputStreamReader ( in : InputStream, charsetName : String) 使用指定字符集創建輸入流
+ InputStreamReader ( in : InputStream, cs : Charset) 使用指定字符集創建輸入流
+ InputStreamReader ( in : InputStream, dec : CharsetDecoder) 使用指定字元解碼集創建輸入流
+ getEncoding() : String 返回當前輸入流使用的字符集名稱
+ read() : int 返回輸入字元的數字
+ read(cbuf : char[], off : int, len : int ) : int 讀取字元到給定字元數組中
+ ready() : boolean 判斷輸入流是否為空
+ close() : void 關閉輸入流

5. ACM模式輸入

5.1 使用Scanner

讀取時有分隔符,默認為空格;輸入時即可轉換,較為方便;

初始化:Scanner sc = new Scanner(System.in);

多行輸入時,while 循環條件可以為 sc.hasNext();

如果確定讀取下一個值的類型,可以直接調用 nextInt() nextDouble() 等方法;

5.2 使用BufferedReader

比Scanner快,但是需要調用別的方法將字元串進行轉換,讀取時也沒有分隔符;

初始化:BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

多行輸入時,可以提前初始化一個字元串變數s,通過 (s = br.readLine() ) != null 進行判斷;

按空格分割 String[] s_array = br.readLine().split(” “);