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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 卜弦 中级黑马   /  2013-10-25 21:20  /  1656 人查看  /  12 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 卜弦 于 2013-10-27 08:21 编辑
  1. import java.io.*;
  2. class FileReaderDemo
  3. {
  4.         public static void main(String[] args) throws IOException
  5.         {
  6.                 FileReader fr = new FileReader("demo.txt");
  7.                
  8.                 char[] buf = new char[1024];

  9.                 int num = 0;
  10.                 int count = 0;
  11.                 while((num=fr.read(buf))!=-1)
  12.                 {
  13.                         count++;
  14.                         System.out.println(new String(buf,0,num));
  15.                 }
  16.                
  17.                 System.out.println("count="+count);
  18.                 fr.close();
  19.         }
  20. }
复制代码
毕老师讲Reader时,读取数据时使用了while循环,这里的while循环很不理解是怎么执行的!
首先,我理解的while是先判断括号中的条件,条件满足才执行大括号中的语句。
我的疑问在于read()返回的是读取的个数,当读到文本内容末尾时返回-1,也就是说在读到文档末尾前,
判断条件都为真,那就是说一直在执行大括号中的语句,但事实上大括号中的语句只执行过一次(count=1)。
所以最后总num应该是等于-1,那么最后输出的时候num=-1,“System.out.println(new String(buf,0,-1))”   这里不是应该有问题吗?但是世上没有,所以给人的感觉是,read方法在读到文档最后一个字符时能知道接下来会返回-1,所以执行了一次大括号中输出语句,然后才返回-1.
经过我自己的验证(请看下面的FileReaderDemo1),这里实际上并不用while循环,我个人感觉while循环加在这里反而有问题。但事实上没有问题。
不知道有没有谁和我有同样的疑问!
  1. mport java.io.*;

  2. class FileReaderDemo1
  3. {
  4.         public static void main(String[] args) throws IOException
  5.         {
  6.                 FileReader fr = new FileReader("demo.txt");
  7.                
  8.                 char[] buf = new char[1024];

  9.                 int num = fr.read(buf);
  10.                
  11.                 System.out.println(new String(buf,0,num));               

  12.                 fr.close();
  13.         }
  14. }
复制代码

评分

参与人数 1技术分 +1 收起 理由
乔兵 + 1

查看全部评分

12 个回复

倒序浏览
您好说实话,我开始学之前也有这样的疑问。
这里是给你举个例子:
public class FileReaderDemo {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("demo.txt");
char[] buf = new char[1024*2];
int len = 0;
int num = fr.read(buf);//将读取到的字符存储到数组中。
System.out.println(num+":"+new String(buf,0,num));
int num1 = fr.read(buf);//将读取到的字符存储到数组中。
System.out.println(num1+":"+new String(buf,0,num1));
int num2 = fr.read(buf);//将读取到的字符存储到数组中。
System.out.println(num2+":"+new String(buf));
fr.close();
}
}
以上对文件操作时总是用num=fr.read(buf);//将读取到的字符存储到数组中。
每次读取一个字节然后就输出:System.out.println(num+":"+new String(buf,0,num));
这样读取一个字符,就输出打印一次,这就让我们想的用循环语句来解决,因为对循环的次数不确定
所以for(){}循环不能使用,因为循环次数是未知数,所以用while(){}循环语句解决问题;

我也测试过while(){}循环体内的语句执行过几次;一下是我的验证代码:
package com.itheima;

import java.io.*;
class FileReaderDemo
{        public static void main(String[] args) throws IOException
        {
                FileReader fr = new FileReader("demo.txt");               
                char[] buf = new char[1024];
                int num = 0;
                int count = 0;
                int i=1;
                while((num=fr.read(buf))!=-1)
                {
                        System.out.println("第"+(i++)+"次进入循环");
                        count++;
                        System.out.println(new String(buf,0,num));
                }               
                System.out.println("count="+count);
                fr.close();
        }
}
打印结果:
第1次进入循环
demo.txt文件内容
count=1

其实这里的while((num=fr.read(buf))!=-1){}
循环num=fr.read(buf))!=-1进行不断的循环判断,一直到读取文件最后-1不符合条件所以没有
将读取到的字符存储到数组中这里的System.out.println(new String(buf,0,num));中的num变量
其实就是缓冲区中数组读取到的字符数组的大小(个数)。
希望对您有帮助。

评分

参与人数 1黑马币 +3 收起 理由
乔兵 + 3

查看全部评分

回复 使用道具 举报
while((len=fr.read(buf))!=-1)
我想可能是判断一下,缓冲池里有没有读到数据,如果读到了才执行大括号中的语句吧!
回复 使用道具 举报
本帖最后由 wenbaoxing 于 2013-10-25 23:19 编辑

你的逻辑出现了问题,你没有对while语句执行正确,请看我的注释:
  1. import java.io.*;

  2. class HeimaTest
  3. {
  4.         public static void main(String[] args) throws Exception
  5.         {
  6.                 FileReader fr = new FileReader("demo.txt");
  7.                
  8.                 char[] buf = new char[1024];

  9.                 int num = 0;
  10.                 int count = 0;
  11.                 while((num=fr.read(buf))!=-1)
  12.                 {
  13.                         count++;
  14.                         System.out.println(new String(buf,0,num));
  15.                         
  16.                         //我在这里加了这条语句,你试一下就明白了
  17.                         //我的解释是:只有while括号中的表达式是true的时候才会进入到循环里面,那如果表达式是true,
  18.                         //则num的值一定是1024或者是最后一次读入的字符长度,也就是说,如果num等于-1之后,根本不会再进入到循环里面了
  19.                         //这样就保证了循环体里面的num的值一定是1024或者是最后一次读入的字符长度
  20.                         System.out.println("num="+num);
  21.                 }
  22.                
  23.                 System.out.println("count="+count);
  24.                 fr.close();
  25.         }
  26. }
复制代码

2.png (65.87 KB, 下载次数: 4)

2.png

2.png (21.83 KB, 下载次数: 3)

2.png

评分

参与人数 1技术分 +1 收起 理由
乔兵 + 1

查看全部评分

回复 使用道具 举报
不知道你想要问的是什么,while的条件是(num=fr.read(buf))!=-1,当文件读到最后num == -1是,while大括号内的就不会执行了啊。而且count=1很可能是因为你用了缓冲区,目标文件比1024要小
回复 使用道具 举报

回复 使用道具 举报
其实之前我也有类似的疑问
现在我简单描述一下,看是否能描述清楚,解决你的问题
while((num=fr.read(buf))!=-1),我们要分析里面的判断条件到底是如何执行和内部的实现方式是什么,因为乍一看,很难看得出来,我们分开按顺序依次执行并解读
循环的结束条件的内部实现机制:
  1. char[] ch = new char[1024];
  2. int num = 0;
  3. while((num=fr.read(ch))!=-1)
  4. {
  5.         System.out.print(new String(ch,0,num));
  6. }
复制代码
我假设你要读取的文件内容有2046个字符(1024*2-2)为什么选这个数有原因,方便理解
当第一次执行while((num=fr.read(ch))!=-1)的时候,从左到右的优先级是fr.read(ch)先执行,是这一次性读取文件中1024个字符(读取数据的时候读到\r\n时还没满1024个字符会自动换行读取,直到满了1024字符),读完后返回一共读了多少个字符,即返回读取数(角标+1),此明显返回的是1024
此时把返回值赋给num,然后判断num是否等于-1,好的不等
此时执行方法体里的输出语句:System.out.print(new String(ch,0,num));输出完毕后
此时再次回到while()判断语句,然后在上次读取结束的地方,准备再次读取1024个字符,不足1024按实际字符算,还剩1022,那么第二次读就一次性读进了1022个,并且返回1022.赋给num,判断num是否等于-1,好的此时不等
接着又是输出语句:System.out.print(new String(ch,0,num));输出完毕后
那么此时文件中没有数据了,fr.read(ch)读不到任何数据,即返回-1,并且还是把-1赋给num,接着判断num是否等于-1,明显此时相等,不执行打印输出
带你走了一遍流程,希望能帮你解惑

评分

参与人数 1技术分 +1 收起 理由
乔兵 + 1

查看全部评分

回复 使用道具 举报
和我有相同的疑惑,就是为什么有时候要用到数组,为什么有时候定义String变量,为什么有时候定义int变量,其实要搞明白这些,就要明白字节流和字符流的的读取方法read()及read()的重载,还要搞明白read()的返回值是什么,有参和无参的read()返回值所代表的意义是有很大差别的,我有总结过,专为解决以上问题,不过我建议楼主还是多自己总结为好,这总机会不多,要好好把握
直接一个粘,再给你修改修改
问题一:为什么有时候时结束条件是“!=-1”,有时候是“!=null”
问题二:返回值到底代表的是什么,为什么有时候能够要定义一个int型的变量去接收返回值,为什么有时候定义String型去接收返回值
对于字符流
BufferedReader有三个Read(),分别是:
int read():返回int型的数据,理解为把读到的字符强转成int返回,即数据的ASCII码,如果到达流末尾返回“-1”
int read(char[] buf):返回读到的字符数量,到达流末尾返回“-1”
(读到的数据存到buf中)
String readLine():返回读到的字符串,如果到达流末尾返回“null”//只有用readLine()才会用null,其余一律用“-1”

FileReader也有三个Read(),分别是:
int read():返回int型的数据,理解为把读到的字符强转成int返回,即字符的ASCII码,如果到达流末尾返回“-1”
int read(char[] buf):返回读到的字符数量,到达流末尾返回“-1”
(读到的数据存到buf中)
int read(char[],int off,int len ):返回读到的字符数量,到达流末尾返回“-1”
(读到的数据存到buf中)
对于字节流
FileInputStream有两个read(),分别是
int read(byte[] bt):返回读到的字节数量,到达流末尾返回“-1”
int read():返回下一字节数据,到达流末尾返回“-1”

BufferedInputStream有两个read(),分别是
int read(byte[],int off,int len):返回读到的字节数量,到达流末尾返回“-1”
int read():返回下一字节数据,到达流末尾返回“-1”
总结:
(1)只有用BufferedReader的readLine()才会用到null,其余一律用“-1”作为结束条件
(2)对于有参数的read()方法里有数组形参“byte[]”“char ch”“byte[],int off,int len”这三种的,返回值都是代表读取到的数据的数目,读到的内容都存到了你所传入的数组里
(3)read()无参数的,分两种讨论
1:字符流:返回int型的数据,理解为把字符强转成int返回,即数据的ASCII码
2:字节流:返回下一字节数据
1.2但两者返回的都是读到的数据,只是数据类型不一样

点评

不错,这里确实需要好好总结,不然会晕的,补充一下readLine( )对应的while循环里写的方法bw.write( )后要加上bw.nextLine( );否则不换行。  发表于 2013-11-17 00:28

评分

参与人数 1黑马币 +1 收起 理由
乔兵 + 1

查看全部评分

回复 使用道具 举报
卜弦 中级黑马 2013-10-27 08:26:00
9#
Jim-剣◆﹏ 发表于 2013-10-25 23:25
其实之前我也有类似的疑问
现在我简单描述一下,看是否能描述清楚,解决你的问题
while((num=fr.read(buf)) ...

握手~~! 我懂了,我还是有点转牛角尖。 请问你是几期的学员?
回复 使用道具 举报
卜弦 发表于 2013-10-27 08:26
握手~~! 我懂了,我还是有点转牛角尖。 请问你是几期的学员?

准28期,我准备27期就去考,哥们你呢
回复 使用道具 举报
卜弦 中级黑马 2013-10-27 09:45:54
11#
Jim-剣◆﹏ 发表于 2013-10-27 08:59
准28期,我准备27期就去考,哥们你呢

我准备27期!在写博客,希望能进。
回复 使用道具 举报
/*
三种方式读取文件
*/

import java.io.*;

public class FileStream
{
        public static void main(String args[])throws IOException
        {
                writeFile();
                //readFile_1();
                readFile_2();
        }
       
        public static void writeFile()throws IOException
        {
                FileOutputStream fos = new FileOutputStream("fileWriter.txt");
               
                fos.write("abcde".getBytes());
                //fos.flush();字节流不需要刷新,以为字节是最小的流单位,不需要再进行转换,而字符流需要刷新
                fos.close();
        }
       
        public static void readFile_1()throws IOException
        {
                FileInputStream fis = new FileInputStream("fileWriter.txt");
               
                int ch =0;
                while((ch=fis.read())!=-1)
                {
                        System.out.println((char)ch);
                }
                fis.close();
        }
       
        public static void readFile_2()throws IOException
        {
                FileInputStream fis = new FileInputStream("fileWriter.txt");
               
                byte[] buf = new byte[1024];
                int len = 0;
               
                while((len=fis.read(buf))!=-1)
                {
                        System.out.println(new String(buf,0,len));
                }
                fis.close();
        }
       
        public static void readFile_3()throws IOException
        {
                FileInputStream fis = new FileInputStream("fileWriter.txt");
               
                byte[] buf = new byte[fis.available()]; //定义一个 刚刚好的缓冲区,数据太太不建议使用
               
                fis.read(buf);
                System.out.println(new String(buf));
                fis.close();
        }
}




















评分

参与人数 1技术分 +1 收起 理由
周志龙 + 1 赞一个!

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马