Scanner, BufferedReader, InputStreamReader 與ACM模式輸入

搬磚的Wayne發表於2021-05-23
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

NameTags
+ 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

NameTags
+ 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

NameTags
+ 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(" ");

相關文章