黑马程序员技术交流社区

标题: IO流这地方还是有点疑惑,求高手帮我详细的解答 [打印本页]

作者: 何明辉    时间: 2012-9-10 20:11
标题: IO流这地方还是有点疑惑,求高手帮我详细的解答
本帖最后由 何明辉 于 2012-9-11 12:44 编辑

import java.io.*;
class FileWriterDemo
{
public static void main(String[] args)throws IOException
{
  Reader p1=new FileReader("文档.text");
  int p11=p1.read();
     int pm=p11&255;//此处取出保留取一个字符的最低八位
  System.out.println((char)p11);
  p1.close();
  InputStream fm=new FileInputStream("文档.text");
  int fm1=fm.read();//读取一个字节
  System.out.println(fm1);
  fm.close();
}
}
上面的程序是为了验证字符流读取一个字符的最低八位是否与字节流读取一个字节的相等。
对于ASC码是不需要验证的,但是当读取的是中文字符怎么就不相等了,上面保留的最低八位不正是字节流读取的一个字节吗
作者: 杨震    时间: 2012-9-10 20:46
本帖最后由 杨震 于 2012-9-10 22:04 编辑
  1. <p>
  2. public static void main(String[] args) throws IOException {
  3.   //使用FileRead的read方法读入并输出每次读的数据十六进制表示
  4.   Reader p1 = new FileReader("文档.txt");
  5.   int p11 = 0;
  6.   while ((p11 = p1.read()) != -1) {
  7.    System.out.println(Integer.toString(p11, 16));
  8.   }
  9.   p1.close();
  10.   
  11.   System.out.println("以上是字符read结果----------");</p><p>  //使用FileInputStream的read方法读入并输出每次读的数据十六进制表示
  12.   InputStream fm = new FileInputStream("文档.txt");
  13.   int fm1 = 0;
  14.   while ((fm1 = fm.read()) != -1) {
  15.    System.out.println(Integer.toString(fm1, 16));
  16.   }
  17.   fm.close();</p><p>  System.out.println("以上是字节read结果----------");
  18.   
  19.   System.out.println(Integer.toString((int) '严', 16));
  20. }
  21. }</p>
复制代码

作者: AngieFans85    时间: 2012-9-10 22:08
假设你的文档.text里的内容为一个"严"字:
你先用Reader类读出一个字符,而文档中确实只有一个"严"字,读出来当然是完整的"严"字.
而用InputStream类每调用一次read()方法,是只读取一个字节,"严"是两个字节组成的一个字符,你只读取一个字节,另外一个字节没有读出来,当然读不出完整的"严"字了.
作者: 杨震    时间: 2012-9-10 22:11
我也很纠结,没有搞明白,为什么字符read和字节read结果不一样
作者: AngieFans85    时间: 2012-9-10 22:29
杨震 发表于 2012-9-10 22:11
我也很纠结,没有搞明白,为什么字符read和字节read结果不一样

去API文档查一查Reader类的read()方法与InputStream类的read()方法,一下就明白了.
作者: 朱烈葵    时间: 2012-9-10 22:32
楼主的意思难道是 FileReader reade()读取一个字符,把它分开为两个字节,记录
使用FileInputStream的read()里读取出一个字节,并和上面的两个对比,想要的结果却没出现
楼主以为 FileReader reade() 读取出来的是 00100010 00100011 这是两个字节 会和FileInputStream的read()里读取出一个字节 里面读取的是一样是00100011
但是结果不是这样,是这样吗,亲爱的楼主,你太有思想了。
作者: 朱烈葵    时间: 2012-9-10 22:34
继续关注这个问题!
作者: 张 涛    时间: 2012-9-10 22:34
字符有问题,换成字母我也不明白。

程序用到的info.txt中是“abc”,程序如下:
  1. Reader p1=new FileReader("info.txt");
  2.                   int p11=p1.read();
  3.                   System.out.println(Integer.toString(p11, 16));
  4.                   p1.close();
  5.                   
  6.                   InputStream fm=new FileInputStream("info.txt");
  7.                   int fm1 = fm.read();
  8.                   int fm2 = fm.read();//读取一个字节
  9.                   System.out.println(Integer.toString(fm1, 16));
  10.                   System.out.println(Integer.toString(fm2, 16));
  11.                   fm.close();
复制代码
字符流读出的是61
字节流读出的是61  61

问题是字符流不应该是读一个字符吗?两个字节,第1个字节是61,第2个字节是62,那么字符流应该读出的是61+62*0x100=0x6261.

原因可能是字符流读的编码方式和字节流读的编码方式不同。还在研究。
作者: 何明辉    时间: 2012-9-10 23:23
不好意思我没有说清楚哦,对于字符流读取中文汉字时,一般默认为一次读取两个字节来对应一个汉字字符,那么我计算出其中读出的第一个字节不正是字节流第一次读取的一个字节吗,两者的值应该相等啊,但上面的程序结果为什么不相等啊,即fm1怎么不等于pm啊
作者: AngieFans85    时间: 2012-9-11 02:03
何明辉 发表于 2012-9-10 23:23
不好意思我没有说清楚哦,对于字符流读取中文汉字时,一般默认为一次读取两个字节来对应一个汉字字符,那么 ...

你的pm是一个字符,字符是两个字节,两个字节就是16位啊,怎么可以将一个字符&上255来得到最低8位(可是有16位的啊)呢,只能用一个字节的数值来&上255得到最低的8位(其实一个字节也就只有8位),这样才能保证每次读取的一个字节不出错.你应该要知道Reader类每调用一次read()方法读取的是一个字符,一个字符你还&上255干什么,直接用char变量来装就是了呗.一个字符&上255,那结果肯定就乱了啊.
fm1不等于pm,那是因为fm1是一个字节,pm是一个字符&上255后得到最低的8位,虽然经过&位操作后,最低8位的二进制没有变化,最高8位全部变成0了,所以一个字符&上255后,最终的二进制结果就只剩下最低8位了,也就是说,一个字符&上255后,最后的结果就被拆成只剩一个字节了(两个字节被拆成只剩一个字节).而一个中文字符被拆成只剩一个字节,这个被拆后所获得的字节,与之前的中文字符一点关系也没有了.
总结:&255操作是用在字节上的,用来保证最终的字节的正确性.但是用在字符上,就不行了,就相当于一个16位的二进制数&上00000000-11111111,那么结果只能得到字符的最低8位,最高8位将被舍弃,因为二进制中任何数&上0,结果都为0.换言之,两个字节组成的字符&上255,最终只剩下一个字节,这样的结果就和&操作之前的字符的值没有任何关系了.
作者: AngieFans85    时间: 2012-9-11 02:08
何明辉 发表于 2012-9-10 23:23
不好意思我没有说清楚哦,对于字符流读取中文汉字时,一般默认为一次读取两个字节来对应一个汉字字符,那么 ...

我相信老毕的视频中,肯定不会将一个字符&上255的,呵呵.
你的研究精神是值得表扬的,加油,如果我是版主,我会给你加分.
作者: AngieFans85    时间: 2012-9-11 02:11
何明辉 发表于 2012-9-10 23:23
不好意思我没有说清楚哦,对于字符流读取中文汉字时,一般默认为一次读取两个字节来对应一个汉字字符,那么 ...

&操作要这样用,给你举个例子吧:
  1. InputStream fm = new FileInputStream("文档.text");
  2.                 int fm1 = fm.read();// 读取一个字节
  3.                 fm1 = fm1 & 255;
复制代码
这样才是正确的用法.
作者: 何明辉    时间: 2012-9-11 09:20
马镱洵 发表于 2012-9-11 02:03
你的pm是一个字符,字符是两个字节,两个字节就是16位啊,怎么可以将一个字符&上255来得到最低8位(可是有16 ...

很感谢帮我积极解答!我比较的正是字符的最低八位和字节流读取的一个字节来做比较,对于字符&255一般确实没有实际意义
作者: AngieFans85    时间: 2012-9-11 10:06
何明辉 发表于 2012-9-11 09:20
很感谢帮我积极解答!我比较的正是字符的最低八位和字节流读取的一个字节来做比较,对于字符&255一般确实 ...

不仅是没有意义,一个字符如果&上255,那么这个字符就被破坏了,这个字符的最高8位也就没有了,原始的字符不就被破坏了吗.
作者: 杨震    时间: 2012-9-11 11:05
何明辉 发表于 2012-9-10 23:23
不好意思我没有说清楚哦,对于字符流读取中文汉字时,一般默认为一次读取两个字节来对应一个汉字字符,那么 ...

昨晚我也弄了半天,由于没有源码,没有完全搞明白,现在我结合网上查的说下自己的想法:

首先:字节流read出来的字节绝对是文件里面真正存在的二进制,所以字节read出来的是没有任何问题的
然后呢:字符read返回的int类型数据,并不是直接将文件里两个字节合并出来的值,而是读取的字符对应的unicode码


比如如:你文档里存了一个"严"字,并且默认文本字符编码是ANSI(中文默认是GBK),此时文件里存的二进制就是D1CF这两个字节(因为"严"的GBK编码就是D1CF),所以你用字节read读两下分别是d1,cf;
但是你用字符read的话,它会将D1CF解析成汉字"严",然后返回汉字"严"对应的unicode码4E25,显然两种流read出来的是不一样的.

我觉得最重要的是要知道字符流read返回的永远是读取的字符的unicode码,而字节流读的是真正的字符存储二进制(如果用unicode存,两者是一样的)

但实际中如果不是用默认的编码存文件,还涉及到文件头的问题,有点复杂,黑马审核群里我上传了一个编码的文档,你自己看下
作者: 何明辉    时间: 2012-9-11 12:11
杨震 发表于 2012-9-11 11:05
昨晚我也弄了半天,由于没有源码,没有完全搞明白,现在我结合网上查的说下自己的想法:

首先:字节流re ...

谢谢啦,回答的太好了,我明白了:是不是对于ASCII表中的所对应的unicode和其在内存中存在的二进制一样,而对于像非ASCII 码比如中文这样后来编进去的码字字符所对应的unicode和其在内存中存在的二进制是不一样的,对吗,
作者: 杨震    时间: 2012-9-11 12:24
本帖最后由 杨震 于 2012-9-11 12:26 编辑

对的,ascii字符好像在各种编码里都是前128个,兼容性好,其他字符就不一样,你看这个文章,讲的非常好http://blog.csdn.net/yangyan19870319/article/details/6131918




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2