【问题标题】:Read all lines with BufferedReader使用 BufferedReader 读取所有行
【发布时间】:2015-05-12 16:37:59
【问题描述】:

我想使用 BufferedReader 在控制台中键入多行文本,然后按“Enter”来查找整个文本长度的总和。问题是我似乎进入了一个无限循环,当我按下“Enter”时,程序并没有结束。我的代码如下:

InputStreamReader instream = new InputStreamReader(System.in);
BufferedReader buffer = new BufferedReader(instream);

    line= buffer.readLine();

    while (line!=null){
        length = length + line.length();
        line= buffer.readLine();
    }

你能告诉我我做错了什么吗?

【问题讨论】:

  • 当你只按回车时,line 将等于 "" 而不是 null。尝试将line != null 更改为!line.equals("")
  • 另外,只是提供一些其他意见(例如使用 for 循环),codereview.stackexchange.com/questions/44135/…
  • 昨晚睡着的时候突然意识到:你用长度干什么?请注意,如果您要执行 cat myfile | java yourprogram 并打印出长度的值,这将与什么不一致,例如wc 打印出来,因为你没有计算换行符。如果您需要这样做,请注意 DOS 文件将具有“\r\n”,而 UNIX 文件将具有“\n”,而我最初使用 System.getProperty("line.separator") 的建议可能不起作用,因为不能保证你不是例如试图在 Linux 下读取 DOS 文件。 (所以,希望这不是你的意思)

标签: java bufferedreader infinite-loop inputstreamreader


【解决方案1】:

来自@Russel Yang (https://stackoverflow.com/a/40412945/11079418) 的好例子。

使用此代码,在每行之后添加一个换行符。

String lines = bufferedReader.lines().map(line -> line + "\n").collect(Collectors.joining());

【讨论】:

    【解决方案2】:

    从 Java 8 开始,您可以直接在缓冲阅读器上使用 BufferedReader#lines 方法。

        try (InputStreamReader in = new InputStreamReader(System.in);
             BufferedReader buffer = new BufferedReader(in)) {
            final int length = buffer.lines().mapToInt(String::length).sum();
            System.out.println("Read length: " + length);
        } catch (Exception e) {
            e.printStackTrace();
        }
    

    【讨论】:

      【解决方案3】:

      将每一行放入 String[] 数组。第二种方法获取文本文件中包含的行数。我希望这对任何人都有用..

      public static void main(String... args) throws IOException {
          String[] data = getLines();
          for(String v : data) {
              out.println(v);
          }
      }
      
      public static String[] getLines() throws IOException {
          BufferedReader bufferReader = new BufferedReader(new FileReader("C:\\testing.txt"));
          String line = bufferReader.readLine(); 
          String[] data = new String[getLinesLength()];
          int i = 0;
          while(line != null) {
              data[i] = line; 
              line = bufferReader.readLine();
              i++;
          }
          bufferReader.close();
          return data;
      }
      
      public static int getLinesLength() throws IOException {
          BufferedReader bufferReader = new BufferedReader(new FileReader("C:\\testing.txt"));
          String line = bufferReader.readLine(); 
          int size = 0;
          while(line != null) {
              size += 1;
              line = bufferReader.readLine();
          }
          bufferReader.close();
          return size;
      }
      

      【讨论】:

        【解决方案4】:

        使用 Java 8 的一行代码:

        line =  buffer.lines().collect(Collectors.joining());
        

        【讨论】:

        • 是否需要包含换行符作为分隔符来保留行?
        • 是的,您必须添加一个可能的分隔符来保留行:buffer.lines() .collect(Collectors.joining(System.lineSeparator()));
        【解决方案5】:

        line在回车时不会为空;它将是一个 字符串。

        注意BufferedReader JavaDocreadLine() 的评价:

        读取一行文本。行被视为由换行符 ('\n')、回车符 ('\r') 或回车符后紧跟换行符中的任何一种来终止。

        然后readLine() 返回:

        包含行内容的字符串,不包括任何行终止字符,如果已到达流的末尾,则为 null

        因此,当您按 [Enter] 时,您将给 BufferedReader 一个仅包含 \n\r\r\n 的新行。这意味着readLine() 将返回一个空字符串。

        所以试试这样吧:

        InputStreamReader instream = new InputStreamReader(System.in);
        BufferedReader buffer = new BufferedReader(instream);
        
        line = buffer.readLine();
        
        while( (line != null) && (!line.isEmpty()) ){
            length = length + line.length();
            line = buffer.readLine();
        }
        

        【讨论】:

        • 我可能错了。但我不认为返回的字符串实际上包含结束行字符。如果是这样,那么 System.out.println(buffer.readLine()); 末尾会有另一行,对吗?
        • 同样在您链接到的 JavaDoc 中:“返回 [...] 行的内容,不包括任何行终止字符”
        • @StephenB 和@RadioDef:我错了!你俩都是对的。我对read() 感到困惑,谁知道呢。
        • while(!line.isEmpty()) {...} like you have before you delete 是正确的......(除了一些人还指出readLine 仍然可以返回 null 如果用户做了一些模糊的事情。)跨度>
        • 我进行了编辑以更正我的答案。 @StephenB 和 RadioDef,感谢你们给我打电话并纠正我,以免我传播错误信息。
        【解决方案6】:

        当你只按 Enter 时,buffer.readLine(); 的返回值不为空,它是一个空字符串。

        因此你应该把line != null改成!line.equals("")(你也可以改成line.length() > 0

        现在您的代码将如下所示:

        InputStreamReader instream = new InputStreamReader(System.in);
        BufferedReader buffer = new BufferedReader(instream);
        
        line = buffer.readLine();
        
        while (!line.equals("")){
            length = length + line.length();
            line = buffer.readLine();
        }
        

        这应该可以解决您的问题。希望这有帮助! :)

        【讨论】:

        • 这确实有效,但由于某种原因,我必须按两次 Enter。知道为什么会这样吗?
        • @deadpixels 当我运行程序时,它在第一个空行处终止。按 Enter 后计数器会上升吗?
        【解决方案7】:

        阅读所有行的惯用方式是while ((line = buffer.readLine()) != null)。另外,我建议try-with-resources statement。类似的东西

        try (InputStreamReader instream = new InputStreamReader(System.in);
                BufferedReader buffer = new BufferedReader(instream)) {
            long length = 0;
            String line;
            while ((line = buffer.readLine()) != null) {
                length += line.length();
            }
            System.out.println("Read length: " + length);
        } catch (Exception e) {
            e.printStackTrace();
        }
        

        如果您想在收到空行时结束循环,请在 while 循环中为此添加测试

        while ((line = buffer.readLine()) != null) {
            if (line.isEmpty()) {
                break;
            }
            length += line.length();
        }
        

        JLS-14.15. The break Statement

        break 语句将控制权转移到封闭语句之外。

        【讨论】:

        • 因为 OP 是从 system.in 读取的,这不会永远结束吗?不就是等用户下次输入吗?
        • @StephenB 它将在 EOF(或 ctrl-d)上结束;也可能使用 ctrl-c 和/或 ctrl-brk。
        • 但我认为他希望它在按 Enter 时结束。
        • 确实不以 Enter 结尾:/
        • @deadpixels 编辑添加break
        【解决方案8】:

        尖刻的回答:你做错的只是在 Java 中创建 2 个对象来做某事......如果你搜索,你可能会找到更多扩展 BufferedReader 或 ExtendedBufferReader 等的类,然后它可以是真正的 Enterprise Java。

        现在我已经从我的系统中得到了这个:更有用的答案。输入EOF时System.in关闭,Linux下是Control-D,我想MacOS,Windows下我 Control-Z加回车。如果你想检查输入(或者更具体地说,两个输入......一个完成最后一行,一个表示你已经完成,这本质上是 http 处理确定 http 标头何时完成以及是时候http 正文,然后@dbank 的解决方案应该是一个可行的选择,我将尝试进行小修复,以将 ! 移动到 while 谓词而不是 !while 中。

        (编辑#2:实现 readLine 去除换行符,所以空行将“”而不是换行符,所以现在我的代码转移到另一个答案,EOF 位作为答案而不是注释)

        编辑...这很奇怪,@dbank 在我输入答案时已经回答了,如果我没有提到 EOF 替代方案,我就会停下来。用我将要进行的编辑从记忆中重复他的代码:

        InputStreamReader instream = new InputStreamReader(System.in);
        BufferedReader buffer = new BufferedReader(instream);
        
            line= buffer.readLine();
            while (line != null && !line.equals("")){
                length = length + line.length();
                line= buffer.readLine();
            }
        

        【讨论】:

        • 致反对的选民:如果这是因为顶部的尖刻回答,字节我(我的意思是,new Byte []("me".getBytes(Charset.forName(" UTF-8")))。否则,我很好奇为什么不赞成:我的代码与其他代码相似(当我发布@dbank 的答案时出现、消失,现在又出现了;你现在在 9 看不到它小时标记,但我的答案在其他人之前发布)并且我还提到了 EOF 选项(这在管道时也很有用)
        猜你喜欢
        • 2013-03-23
        • 2018-06-16
        • 2017-11-18
        • 1970-01-01
        • 2019-10-17
        • 2013-10-30
        • 2019-01-09
        • 1970-01-01
        • 2017-07-16
        相关资源
        最近更新 更多