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