A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 啷个里个郞 于 2012-5-12 10:52 编辑

package cn.itcast.day01;

import java.io.*;

public class O {


        static class ReflectTest  {
                public static void main(String[] args) throws IOException
                {
                        FileWriter fw = new FileWriter("123.txt");
                        fw.write("abcdefg");
                        fw.close();  

                        FileReader fr = new FileReader("123.txt");
                        System.out.println((char)fr.read());
                        
                        System.out.println((char)fr.read());
                        
                        System.out.println((char)fr.read());
                        fr.close();
                        System.out.println((char)fr.read());    //不明白的是为什么连最后一条语句都会读取出来,上面语句不是关闭此流资源了吗?
                }
        }
}

5 个回复

倒序浏览
close()关闭该流并释放资源,关闭后再调用read()将抛出IOException

点评

谢谢  发表于 2012-5-12 10:50
回复 使用道具 举报
close()关闭该流并释放资源,同时会在刷新一次,所以  fr.close(); 后的一句 System.out.println((char)fr.read());  会被打印。
同时如果你在 后面在添加一句 System.out.println((char)fr.read()); 的话 就会报异常信息了

点评

谢谢  发表于 2012-5-12 10:50
回复 使用道具 举报
原因是字符流是对字节流的包装。它里面多了个缓存,缓存很小只有两个byte(因为char有两个byte),而英文字母却只用了一个byte的,编译系统默认的是UTF-8的,允许Unicode码在硬盘文件存取字母时用一个byte。第一次调用read方法时,字符流会从文件中读取两个byte,并存放在缓存中,然后把第一个byte转换成int返回;第二次调用read方法时,会直接到缓存中找,返回第二个byte。第三次时,会再文件中读取两个byte,返回第一个byte。以此类推,第四次调用read方法时,就算关了流,read方法回到内存中找,而不是去文件中找。所以上面的代码运行没有出错。如果再加一行 “System.out.println((char)fr.read()); ”就会出错。
static class ReflectTest  {
            public static void main(String[] args) throws IOException
            {
                    FileWriter fw = new FileWriter("123.txt");
                    fw.write("abcdefg");
                    fw.close();  

                    FileReader fr = new FileReader("123.txt");
                    System.out.println((char)fr.read());
                    
                    System.out.println((char)fr.read());
                    
                    System.out.println((char)fr.read());
                    fr.close();
//                    System.out.println((char)fr.read());
                    System.out.println((char)fr.read());    //不明白的是为什么连最后一条语句都会读取出来,上面语句不是关闭此流资源了吗?
            }
    }
}

点评

谢谢  发表于 2012-5-12 10:51
回复 使用道具 举报
这个问题问的好,之前我也没有注意过,按理说,楼主的代码应该会抛异常的,但事实上却没有,原因为:
fr.read()方法,查源码会发现,他最终是调用 StreamDecoder 类的read0 方法,

   36   public class StreamDecoder extends Reader
   37   {
                ....

  111       public int read() throws IOException {
  112           return read0();
  113       }
  114   
  115       private int read0() throws IOException {
  116           synchronized (lock) {
  117   
  118               // Return the leftover char, if there is one
  119               if (haveLeftoverChar) {
  120                   haveLeftoverChar = false;
  121                   return leftoverChar;
  122               }
  123   
  124               // Convert more bytes
  125               char cb[] = new char[2];
  126               int n = read(cb, 0, 2);
  127               switch (n) {
  128               case -1:
  129                   return -1;
  130               case 2:
  131                   leftoverChar = cb[1];
  132                   haveLeftoverChar = true;
  133                   // FALL THROUGH
  134               case 1:
  135                   return cb[0];
  136               default:
  137                   assert false : n;
  138                   return -1;
  139               }
  140           }
  141       }

从 125-126行可以看出,read方法,其实是是每次read 2个字符,但只返回了一个,再次调用read方法时,其实并没有读文件,而是将缓存中的字符返回给用户了。

楼主的代码在fr.close()之前调用了三次read 此时还有一个字符在缓存中,第4次调用read方法时,并没有真的去读文件,所以没有抛异常,如果楼主的代码,再多读一次read方法,就会抛异常了。

点评

大爱啊。谢谢。谢谢。  发表于 2012-5-12 10:51

评分

参与人数 1技术分 +1 收起 理由
职业规划-刘倩老师 + 1 赞一个!

查看全部评分

回复 使用道具 举报
本帖最后由 张晨 于 2012-5-12 10:02 编辑

这是一个小BUG,本意是为了效率多读一个char。也就是说只要有可能read()就读两个字符(就是上面代码中read(cb, 0, 2)),一个输出一个放缓存,如果第二次调用read()方法,他会直接调用缓存缓存,而不会调用更加底层的implRead(cbuf, off, off + len),而后把缓存置为空。 所以也就不会检测此流是否已经被关闭了!
楼主代码在第二次read()的时候,close(),然后在read()是会抛出异常的。{:soso_e100:}

点评

谢谢  发表于 2012-5-12 10:51
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马