系统输出
学完了PrintStream PrintWriter之后我们会发现里面方法很熟悉,例如:print() println() 实际上在之前使用的系统输出就利用了IO流模式完成的,在System类中定义有三个操作的常量:
标准输出(显示器):public static final PrintStream out
错误输出:public static final PrintStream err
标准输入(键盘):public static final InputStream in
原来之前使用的System.out.println()一直都属于IO的操作范畴。
系统输出
系统输出有两个常量:out err 而且这两个常量所表示的都是PrintStream类的对象,从Java的设计本质上来讲,这样的两种输出有以下的设计目的:out输出的是希望用户可以看见内容,err是希望输出用户不能看见的内容。
这两种输出在实际的开发之中都没用。
1 package cn.Tony.demo; 2 3 public class TestDemo{ 4 public static void main(String[] args) throws Exception { 5 try { 6 Integer.parseInt("abc"); 7 }catch(Exception e) { 8 System.err.println(e); 9 System.out.println(e); 10 } 11 12 } 13 }
System.err也只是作为一个保留的属性提供存在。System.out属于PrintStream,属于OutputStream
范例:
1 package cn.Tony.demo; 2 3 import java.io.OutputStream; 4 5 public class TestDemo{ 6 public static void main(String[] args) throws Exception { 7 OutputStream out=System.out; 8 out.write("世界和平".getBytes()); 9 } 10 }
抽象类不同的子类针对同一方法有不同的实现,用户调用的时候的核心参考的就是OutputStream。
系统输入 in
System.in对于的类型是InputStream,而这种的输入流指的是由用户通过键盘进行输入(用户输入),java本身并没有这种直接的用户输入处理,如果要想实现这种输入处理必须用java.io的模式完成
范例:利用InputStream
1 package cn.Tony.demo; 2 3 import java.io.InputStream; 4 5 public class TestDemo{ 6 public static void main(String[] args) throws Exception { 7 InputStream input=System.in;//为父类实例化 8 byte data[]=new byte[1024];//开辟一个空间 9 System.out.println("请输入信息:"); 10 int temp=input.read(data);//数据读取到字节数组中 11 System.out.println("【ECHO】输入内容:"+new String(data,0,temp)); 12 13 } 14 }
现在发现当用户输入数据的时候需要暂停执行,也就是说程序进入到阻塞状态,直到用户输入完成(按下回车),那么才能向下执行,但是以上的程序本身有一个致命的问题,那么核心点就在于:要开辟的字节数组的长度是固定的,输入内容超过了该长度。如果开辟的量超过长度,只能接受部分数据,保存内存流,
1 package cn.Tony.demo; 2 3 import java.io.ByteArrayOutputStream; 4 import java.io.InputStream; 5 6 public class TestDemo{ 7 public static void main(String[] args) throws Exception { 8 InputStream input=System.in;//为父类实例化 9 ByteArrayOutputStream bos=new ByteArrayOutputStream(); 10 byte data[]=new byte[1024];//开辟一个空间 11 System.out.println("请输入信息:"); 12 int temp=0; 13 while((temp= input.read(data))!=-1) { 14 //这里面需要由用户自己来处理换行的问题,因为换行不属于文件结束,所有内容不是-1 15 bos.write(data,0,temp); 16 if(temp<data.length) { 17 break; 18 } 19 } 20 System.out.println("【ECHO】输入内容:"+new String(bos.toByteArray())); 21 bos.close(); 22 input.close(); 23 } 24 }
虽然实现了键盘输入数据的功能,不过整体逻辑混乱,也就是说java本身所提供的System.in该操作不好用
1 package cn.Tony.demo; 2 import java.io.InputStream; 3 public class TestDemo{ 4 public static void main(String[] args) throws Exception { 5 InputStream input=System.in;//为父类实例化 6 StringBuffer buf=new StringBuffer(); 7 System.out.println("请输入信息:"); 8 int temp=0; 9 while((temp= input.read())!=-1) { 10 if(temp==' ') { 11 break; 12 } 13 buf.append((char)temp); 14 } 15 System.out.println("【ECHO】输入内容:"+buf); 16 input.close(); 17 } 18 }
通过以上的比较可以感受到System.in的支持度原本不高,对于英文的操作该勉强可以使用,所以要中文,就必须结合内存流来完成,所以复杂度 是很高的,如果开发都这么写,就非常麻烦了
总结:
如果要想在IO中进行中文的处理,那么最好的做法是将所有输入的数据保存在一起再处理,这样才可以保证出现乱发,
BufferedReader类属于一个缓冲的输入流,字符流的操作对象,但是必须清楚一点,对于缓冲流在java.io中定义有两类:字节缓冲流(BufferedInputStream),字符缓冲流(BufferedReader)。
之所以选择BufferedReader类操作是因为在此类中提供的readLine()方法,这个方法可以直接读取一行数据(以回车为换行符)
读取一行:public String readLine()throws IOException
但是如果要想去使用BufferedReader类有一个问题需要注意了,来观察一下BufferdReader
范例;利用BufferedReader实现键盘输入
1 package cn.Tony.demo; 2 3 import java.io.BufferedReader; 4 import java.io.InputStreamReader; 5 6 public class TestDemo{ 7 public static void main(String[] args) throws Exception { 8 BufferedReader buf=new BufferedReader(new InputStreamReader(System.in)); 9 System.out.println("请输入信息:"); 10 //默认的换行模式是BufferedReader最大缺点,如果不是因为此缺点,该类还好继续使用 11 String str=buf.readLine();//接受输入信息,默认用回车换行 12 System.out.println(str); 13 } 14 }
使用以上的形式实现的键盘输入还有一个最大的特点 ,由于接受的数据类型为String,那么也就证明可以使用正则判断。利用String类的各种操作进行处理,还可以变为各种常用的数据类型,
1 package cn.Tony.demo; 2 3 import java.io.BufferedReader; 4 import java.io.InputStreamReader; 5 6 public class TestDemo{ 7 public static void main(String[] args) throws Exception { 8 BufferedReader buf=new BufferedReader(new InputStreamReader(System.in)); 9 System.out.println("请输入信息:"); 10 //默认的换行模式是BufferedReader最大缺点,如果不是因为此缺点,该类还好继续使用 11 String str=buf.readLine();//接受输入信息,默认用回车换行 12 if(str.matches("\d{1,3}")) { 13 System.out.println("【ECHO】输入信息为:"+Integer.parseInt(str)); 14 }else { 15 System.out.println("输入的数据有错误"); 16 } 17 } 18 }
在很多的开发中依然可能会发现有BufferedReader类的身影,但是这个类随着时间的偏移,基本上使用的频率已经很低了。已经被新的类Scanner所取代了,
总结
BufferedReader类读取数据很方便(readLin)。
Scanner
打印流解决的是OutputStream缺陷,BufferedRead解决的是InputStream的缺陷,而java.Util.Scanner解决的是BufferedReader类的一个缺陷。
Scanner是一个专门进行输入流处理的程序类,利用这个类可以方便处理数据类型。同时也可以直接结合正则表达式进行各项处理。在这个类中关注一下:
判断是否有指定类型的数据:public boolean hasNextXxx()
取得指定类型的数据:public 数据 nextXxx()
定义分隔符:public Scanner useDelimiter(Pattern pattern)
构造方法:public Scanner(InputStream source)
范例:使用Scanner实现数据的输入
1 package cn.Tony.demo; 2 3 import java.util.Scanner; 4 5 public class TestDemo{ 6 public static void main(String[] args) throws Exception { 7 Scanner scan=new Scanner(System.in); 8 System.out.println("请输入数据:"); 9 if(scan.hasNext()) {//现在有输入内容,不判断空字符串 10 System.out.println("【ECHO】输入内容为:"+scan.next()); 11 } 12 scan.close(); 13 } 14 }
使用Scanner输入还可以接收各种数据类型
范例:
1 package cn.Tony.demo; 2 3 import java.util.Scanner; 4 5 public class TestDemo{ 6 public static void main(String[] args) throws Exception { 7 Scanner scan=new Scanner(System.in); 8 System.out.println("请输入数据:"); 9 if(scan.hasNextInt()) {//现在有输入内容,不判断空字符串 10 int age=scan.nextInt(); 11 System.out.println("【ECHO】输入内容为:"+age); 12 }else{ 13 System.out.println("ERROR:输入不是数字"); 14 } 15 scan.close(); 16 } 17 }
最为重要的文图它可以对接收的数据类型使用正则表达式进行判断。
范例:利用正则进行判断
1 package cn.Tony.demo; 2 3 import java.util.Scanner; 4 5 public class TestDemo{ 6 public static void main(String[] args) throws Exception { 7 Scanner scan=new Scanner(System.in); 8 System.out.println("请输入数据:"); 9 if(scan.hasNext("\d{4}-\d{2}-\d{2}")) { 10 String birthday=scan.next(); 11 System.out.println("生日:"+birthday); 12 }else { 13 System.out.println("错误"); 14 } 15 scan.close(); 16 } 17 }
但是以上的操作在开发中不会出现,
使用Scanner本身能接收的是一个InputStream类的对象,例如:文件输入流。
1 package cn.Tony.demo; 2 import java.io.File; 3 import java.io.FileInputStream; 4 import java.util.Scanner; 5 public class TestDemo{ 6 public static void main(String[] args) throws Exception { 7 Scanner scan=new Scanner(new FileInputStream(new File("D:"+File.separator+"IO"+File.separator+"data.txt"))); 8 scan.useDelimiter(":"); 9 while(scan.hasNext()) { 10 System.out.println(scan.next()); 11 } 12 scan.close(); 13 } 14 }
Scanner实际上完美的替代了BufferedReader,更好的实现了InputStream操作。
总结:
以后除了二进制的文件拷贝处理之外,那么只要是针对于程序的信息输出都是用打印流。信息输入都使用Scanner