第十三章 使用Scanner扫描器比使用io流更方便?
使用Scanner扫描器比使用io流更方便?
使用流读取/写入文件是我最常用的处理方式,今天又新学习了一种使用扫描【Scanner】输入的方法。
对于读取一行文本,对其进行分词【Scanner分词定界符了解更多】,下面这种方式比较麻烦:
1 package 字符串; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.StringReader; 6 import java.util.Scanner; 7 8 /** 9 * 扫描输入与使用流读入对比 10 * 11 * 12 * @author admin 13 * 14 */ 15 public class Scan { 16 17 public static final String STR = "Sir Robin of Camelot\n22 1.61803 0.897"; 18 19 public static void main(String[] args) { 20 io(); 21 } 22 23 public static void io() { 24 BufferedReader br = new BufferedReader(new StringReader("Sir Robin of Camelot\n22 1.61803 0.897")); 25 try { 26 //读入一行 27 String name = br.readLine(); 28 System.out.println(name); 29 30 //只能一行一行读入,然后再对一行中的数据进行处理 31 String str = br.readLine().replaceAll(" +"," "); 32 System.out.println(str); 33 34 String[] split = str.split(" "); 35 System.out.println(Integer.parseInt(split[0])); 36 System.out.println(Double.parseDouble(split[1])); 37 System.out.println(Double.parseDouble(split[2])); 38 39 } catch (IOException e) { 40 e.printStackTrace(); 41 }finally { 42 try { 43 if(br!=null) { 44 br.close(); 45 } 46 }catch(IOException e) { 47 e.printStackTrace(); 48 } 49 } 50 } 51 52 }
控制台:
Sir Robin of Camelot
22 1.61803 0.897
22
1.61803
0.897
用上面这种方式,你可以看到,如果你想提取一行里的数据,只能使用一些小手段,先将他们分割,然后再取出,在转为你想要的类型,操作代码比较繁琐,而且你还要去处理异常。
使用Scanner【java.util.Scanner】扫描器就方便了许多,它的优点看下面代码分析:
1 package 字符串; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.StringReader; 6 import java.util.Scanner; 7 8 /** 9 * 扫描输入与使用流读入对比 10 * 11 * 12 * @author admin 13 * 14 */ 15 public class Scan { 16 17 public static final String STR = "Sir Robin of Camelot\n22 1.61803 0.897"; 18 19 public static void main(String[] args) { 20 scan(); 21 backUpRead(); 22 } 23 24 25 @SuppressWarnings("resource") 26 public static void scan() { 27 Scanner scanner = new Scanner(Scan.STR); 28 29 //nextLine()读取下一行的内容,并且指针向下移动一行 30 System.out.println(scanner.nextLine());//只认换行符,不认我直接换行 31 32 //nextInt()/nextDouble()指针不会在向下移动,而是水平移动。 33 System.out.println(scanner.nextInt()); 34 System.out.println(scanner.nextDouble()); 35 System.out.println(scanner.nextDouble()); 36 37 38 //当找不到本行内下一个值时会抛出异常。找不到下一行时也会抛出异常 39 //System.out.println(scanner.nextDouble()); 40 //System.out.println(scanner.nextLine()); 41 42 //Scanner有一个假设,在输入结束时会抛出IOException,所以Sanner会把IOExecption吞掉 43 System.out.println(scanner.ioException()); 44 } 45 46 public static void backUpRead() { 47 Scanner scanner = new Scanner(System.in); 48 49 System.out.println("你叫什么名字呀?"); 50 System.out.println(scanner.next()); 51 52 System.out.println("你家住哪呀?"); 53 System.out.println(scanner.next()); 54 55 } 56 57 }
控制台:
Sir Robin of Camelot 22 1.61803 0.897 null 你叫什么名字呀? 毛毛 毛毛 你家住哪呀? 上海 上海
Scanner有许多重载的构造器,所有你想使用的流【文件流,缓存流等等】【这里的流指的是输入流】,都可以在最外层套上扫描器。这样你不仅可以方便的使用readLine()方法,而且对于分词的处理更加方便,从上面代码中也可以看到在使用读取下一行方法next()时以及读取本行内数据nextInt()/nextDouble等方法时并不需要你去写try-catch块。因为Scanner有一个假设,在输入结束时会抛出IOException,所以Scanner会把IOException吞掉【你可以通过ioException()方法,找到最近发生的异常,在必要时刻你可以去检查它】,这样你就没必要每次都去写try-catch块了。想关闭流的话,你可以专门写一个方法,将流对象传入,在这个关闭流对象的方法里将流关闭。
在输入结束时吞掉异常:它并不会吞掉你自己操作导致的异常,就像上面带代码39或40行那样,没有经过hasNextDouble()方法的判断,就直接使用,导致抛出NoSuchElemetmentException异常,它并不会帮你吞掉,所以最好的办法是先判断,在使用。只要不是你非法操作导致的问题,Scanner还是很乐意为您效力的。
Scanner套接字节流或字符流:
字节流的套接:在Scanner的构造方法中Scanner(InputStream source),InputStream只要经过适当的套接,总能获得你想要的流接口。
字符流的套接:Scanner(Readable source),你需要使用Java SE5中新加入的一个接口Readable,该接口表示“具有read()方法的某种东西”,查看Readable接口的API你可以发现你想要的带有Reader的类基本都在其中。
附:
用正则表达式扫描【不允许你的正则表达式中出现定界符,Scanner默认的定界符也不能出现】:
1 package 字符串; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.StringReader; 6 import java.util.Scanner; 7 import java.util.regex.MatchResult; 8 import java.util.regex.Matcher; 9 import java.util.regex.Pattern; 10 11 /** 12 * 13 * @author admin 14 * 15 */ 16 public class Scan { 17 18 public static void main(String[] args) { 19 scanByRegex(); 20 } 21 22 public static void scanByRegex() { 23 String str = "58.27.90.129@02/10/2005\n"+ 24 "67.12.20.234@24/07/2006\n"; 25 Scanner sc = new Scanner(str); 26 Pattern pattern = Pattern.compile("(\\d+[.]\\d+[.]\\d+[.]\\d+)@(\\d{2}/\\d{2}/\\d{4})"); 27 while(sc.hasNext(pattern)) { 28 System.out.println(sc.next(pattern)); 29 MatchResult match = sc.match(); 30 String ip = match.group(1); 31 String date = match.group(2); 32 System.out.format("Thread on %s from %s\n", date,ip); 33 } 34 } 35 36 }
控制台:
58.27.90.129@02/10/2005 Thread on 02/10/2005 from 58.27.90.129 67.12.20.234@24/07/2006 Thread on 24/07/2006 from 67.12.20.234