在 while 循环中正确使用 BufferedReader.readLine()

Posted

技术标签:

【中文标题】在 while 循环中正确使用 BufferedReader.readLine()【英文标题】:Using BufferedReader.readLine() in a while loop properly 【发布时间】:2012-11-04 13:01:40 【问题描述】:

所以我在将文本文件读入我的程序时遇到了问题。代码如下:

try 
    InputStream fis = new FileInputStream(targetsFile);
    BufferedReader br = new BufferedReader(new InputStreamReader(fis));

    //while(br.readLine()!=null)
    for (int i = 0; i < 100; i++) 
        String[] words = br.readLine().split(" ");
        int targetX = Integer.parseInt(words[0]);
        int targetY = Integer.parseInt(words[1]);
        int targetW = Integer.parseInt(words[2]);
        int targetH = Integer.parseInt(words[3]);
        int targetHits = Integer.parseInt(words[4]);
        Target a = new Target(targetX, targetY, targetW, targetH, targetHits);
        targets.add(a);
    
    br.close();
 catch (Exception e) 
    System.err.println("Error: Target File Cannot Be Read");

我正在读取的文件是 100 行参数。如果我使用 for 循环,它会完美运行。如果我使用 while 语句(在 for 循环上方注释掉的那个),它会在 50 处停止。用户有可能使用具有任意行数的文件运行程序,因此我当前的 for 循环实现不会没用。

为什么while(br.readLine()!=null) 行在 50 处停止?我检查了文本文件,没有任何东西可以挂断它。

当我使用 while 循环时,我没有从 try-catch 中得到任何错误,所以我很难过。有人有什么想法吗?

【问题讨论】:

【参考方案1】:

您在循环内第二次调用br.readLine()。 因此,您每次四处走动时都会阅读 行。

【讨论】:

谢谢!我绝对应该注意到这一点。你知道解决方法是什么吗? ((line = br.readLine()) != null) 语法在 Java 中是允许的,对吧? @jpm:是的;这是最好的方法。 (虽然我喜欢把null放在第一位,这样更清楚) @SLaks 我同意,yoda 条件更安全,但我就是不习惯写它们 :) @jpm:我不是说为了安全(Java 有一个编译器错误);我的意思是说清楚那里有一个任务。【参考方案2】:

感谢 SLaks 和 jpm 的帮助。这是一个非常简单的错误,我根本没有看到。

正如 SLaks 所指出的,br.readLine() 在每个循环中被调用两次,这使得程序只能获得一半的值。这是固定的代码:

try
        InputStream fis=new FileInputStream(targetsFile);
        BufferedReader br=new BufferedReader(new InputStreamReader(fis));
        String words[]=new String[5];
        String line=null;
        while((line=br.readLine())!=null)
            words=line.split(" ");
            int targetX=Integer.parseInt(words[0]);
            int targetY=Integer.parseInt(words[1]);
            int targetW=Integer.parseInt(words[2]);
            int targetH=Integer.parseInt(words[3]);
            int targetHits=Integer.parseInt(words[4]);
            Target a=new Target(targetX, targetY, targetW, targetH, targetHits);
            targets.add(a);
        
        br.close();
    
    catch(Exception e)
        System.err.println("Error: Target File Cannot Be Read");
    

再次感谢!你们太棒了!

【讨论】:

还展示了对字符串不变性的巨大利用。【参考方案3】:

也很全面...

try
    InputStream fis=new FileInputStream(targetsFile);
    BufferedReader br=new BufferedReader(new InputStreamReader(fis));

    for (String line = br.readLine(); line != null; line = br.readLine()) 
       System.out.println(line);
    

    br.close();

catch(Exception e)
    System.err.println("Error: Target File Cannot Be Read");

【讨论】:

这就是我要走的路。 while((line=br.readLine())!=null) 太丑了。我不喜欢两次致电br.readLine(),但您对此无能为力。我只是将for 语句缩短为for (String s = br.readLine(); s != null; s = br.readLine()) 我喜欢 for 循环语法,因此循环后没有变量。它也可以缩短一点,仍然有点难看:for ( String line = null; null != (line = reader.readLine()); ) 注意: 在条件中使用reader.readLine()for 的初始化程序会导致第一行被跳过。跨度> 我不太了解java,所以这可能不是最干净的解决方法,但是当程序无法打开文件时,它应该给出一个有用的错误消息来解释原因。换句话说,不要丢掉重要的信息;将其包含在错误消息中。例如,System.err.println("Error: Target File Cannot Be Read" + e); 它不会占用大量内存,因为在每个循环中它都会创建一个字符串对象并将引用“行”分配给该对象,并且还会将旧的字符串对象进行垃圾收集。我们所有的字符串都是不可变的。我们不能以某种方式使用 StringBuilder【参考方案4】:

您可以使用如下结构:

 while ((line = bufferedReader.readLine()) != null) 
            System.out.println(line);
        

【讨论】:

【参考方案5】:

如果您仍然对这个问题感到困惑。 如今,Java 8 看起来更好:

try 
  Files.lines(Paths.get(targetsFile)).forEach(
    s -> 
      System.out.println(s);
      // do more stuff with s
    
  );
 catch (IOException exc) 
  exc.printStackTrace();

【讨论】:

【参考方案6】:

概念解决方案:br.read() 返回特定字符的 int 值所以循环 继续,直到我们不会得到 -1 作为 int 值,因此它会打印到那里 br.readLine() 以字符串形式返回一行。

    //Way 1:
    while(br.read()!=-1)
    
      //continues loop until we won't get int value as a -1
      System.out.println(br.readLine());
    

    //Way 2:
    while((line=br.readLine())!=null)
    
      System.out.println(line);
    

    //Way 3:
    for(String line=br.readLine();line!=null;line=br.readLine())
    
      System.out.println(line);
    

方式 4: 这是一种使用集合和数组概念读取文件的高级方法 我们如何迭代使用每个循环。 在这里检查 http://www.java67.com/2016/01/how-to-use-foreach-method-in-java-8-examples.html

【讨论】:

欢迎来到SO,请解释你的答案,不要只发布源代码sn-p【参考方案7】:

除了@ramin 给出的答案,如果你已经有BufferedReaderInputStream,可以这样遍历行:

reader.lines().forEach(line -> 
    //...
);

或者如果您需要按照给定的顺序处理它:

reader.lines().forEachOrdered(line -> 
    //...
);

【讨论】:

以上是关于在 while 循环中正确使用 BufferedReader.readLine()的主要内容,如果未能解决你的问题,请参考以下文章

如何在while中正确循环?

在 Scala 中编写 read-while 循环的正确方法是啥?

在 for 循环和 while 循环中正确索引

正确地在while循环中使用BufferedReader.readLine()

如何使用while循环正确修改整数

如何在while内部正确循环