• 热门专题

System.in和System.out详解

作者:  发布日期:2014-06-03 20:26:22
Tag标签:System  in和System  out详解  
  • 案例1:

     

    InputStream in=System.in;
    OutputStream os=System.out;
    int len=0;
    while((len=in.read())!=-1){
    	os.write(len);
    	os.flush();
    }
    先来看上面一段代码,都是字节流,而且是一个字节的读,一个字节的写,如果我们在控制台输入汉字,为什么能正常输出汉字。

     

    首先我们要明白:

    1.System.out.println()方法打印出的是原始数据,输入什么就在控制台或文件中显示什么,例如System.out.println(110); 那么在控制台就打印110

    2.而输出流的write()方法输出的是ascii值,控制台或文件中显示的是转换后的数据,例如 fos.write(110); 在控制台打印的是经过ASCII转换后的 n

    3.我们输入的回车符是由两个字符组成,回车和换行,对应的ASCII分别是,回车--13,换行--10

    4.键盘上的回车对应两个字符,一个回车,一个换行,回车表示确认标识并换行,换行就是换一行,两个在一起只表现回车

    案例2:

    看一个演示例子

     

    <span style="white-space:pre">		</span>InputStream in=System.in;
    		OutputStream os=System.out;
    		int len=0;
    		while((len=in.read())!=-1){
    			System.out.println(len);
    			os.write(len);
    			os.flush();
    		}
    输入 1 ( int类型 1),输出结果:

     

    第1行:49

    第2行:113

    第3行:

    第4行:10

    第5行:

    第6行:

    结果分析:

    一)1对应的ASCII表值是49,回车--13,换行--10,read读取到1,len=49,System.out.println(49)输出原始数据len的值49,然后换行,write(49),输出转换后的值1,不换行

    二)因为在输入1后,我们敲了一个回车符,产生了两个字符,一个回车,一个换行,read读取到回车符,len=13,System.out.println(13)输出原始数据len的值13,然后换行,write(13),输出转换后的值 换行,所以第3行是空的

    三)read读取到换行符,System.out.println(10)输出原始数据len的值10,然后换行,write(10)输出转换后的值换行,所以最后标记是落在第6行

    案例3:

    有了以上的分析,再来看输入汉字的情况(为了方便分析,每次打印结果不换行,System.out.print() )

    输入 你 ( 汉字 ) , 输出结果:

    196?27?3
    10

    结果分析:

    看到结果就会有疑问,回车符13的1了,所以结果肯定出现了占位情况。汉字 “你” 的ASCII表对应的值是:11000100 11100011,转成十进制分别是196和227,我们期望的结果是196?227?13 10。

    一)汉字 你 两个字节,第一个字节196,System.out.print(196),原样打印出196,write(196),查表196没有对应的字符,所以打印出 ?

    二)本来第二步应该是执行write(196),输出?号,可观察结果发现,2被覆盖了,所以,第二步并不是执行write,而是去查表,同时循环继续运行,输出227,13.....

    三)这时的输出结果是19622713,然后查表结果也返回了,返回两个问号,在本来要插入的位置上插入,所以就产生了占位情况

    四)输入一长串的汉字,结果中发现,查表速度有时快有时慢,中间也会出现先输出?号不占位的情况

    五)对于汉字这种多字节的字符,是先输出原始数值,再查表替换

    案例4:

    再看另外一种情况(输入字节数是偶数,缓冲数组长度是奇数)

     

    <span style="white-space:pre">		</span>InputStream in=System.in;
    		OutputStream os=System.out;
    		int len=0;
    		byte[] buf=new byte[3];
    		while((len=in.read())!=-1){
    			for(byte b:buf){
    				System.out.println(i);
    			}
    			os.write(b,0,len);
    			os.flush();
    		}
    for循环用户打印当前缓冲数组中的字节

     

    输入:你好

    结果:

    -60
    -29
    -70
    你?61
    13
    10
    ?


    结果分析:一看结果出现了占位情况

    一)你好 的字节字节码分别是 196 227 和185 195,因为是byte数组,单字节,所以表现为-60 -29和-70 -61,

    二)结果先输出-60 -29 -70 -61因为缓冲数组只有三个字节,所以查表时也只是拿这三个字节去查表,输出 你和?,但是为什么只覆盖了一个字节了,按照案例:3的分析,应该是覆盖两个字节,那么解释就是:因为是负数,已经知道是汉字,所以对于第一个已存在的汉字查找很快,但是第二个只知道一个字节,jvm仍以为存在一个汉字与之对应,所以会搜索全部汉字,最后发现没有对应的汉字,所以才输出?第一个搜索耗时较短,所以执行到write先输出第一个汉字,然后一边搜索另一个汉字,一边继续继承程序,这就造成了只覆盖一个负号的情况

    三)如果在write()后让线程休眠一会,就可以看到不会发生占位的情况

     

    <span style="white-space:pre">		</span>InputStream in=System.in;
    		OutputStream os=System.out;
    		int len=0;
    		byte[] b=new byte[3];
    		while((len=in.read())!=-1){
    			for(byte i:b){
    				System.out.println(i);
    			}
    			Thread.sleep(1);
    			os.write(b,0,len);
    			os.flush();
    		}
    四)对于这种情况,如果不加for循环,也能正常输出汉字,这是因为读取到负数,知道是汉字,而缓冲数组中只有三个字节,这时会先拿前两个字节去码表中寻找,找到一个汉字返回,至于剩下的一个字节,会先拿一个字节去匹配码表,在码表匹配完之前下一个字节仍不出现,那么就返回?号,如果在未匹配完之前下一个字节出现,那么会用这两个字节重新在码表中匹配,(或者是直到下一个字节的出现才去匹配码表,如果等待超时,则返回?号),下面这段代码可以说明,在只有一个字节时有个等待过程,等待超时,则返回?号。

     

     

    InputStream in=System.in;
    OutputStream os=System.out;
    int len=0;
    byte[] b=new byte[3];
    while((len=in.read())!=-1){
    	os.write(b,0,len);
    	Thread.sleep(1);
    	os.flush();
    }


About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规