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 = "hello fish 1 fish 2.33 fish"; Scanner fromString = new Scanner(input).useDelimiter("\\s*fish\\s*"); String s2 = fromString.next(); int a2 = fromString.nextInt(); double b2 = fromString.nextDouble(); System.out.println(s2 + " " + a2 + " " + 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(” “);