为什么BufferedReader.readLine可以读取一条没有行分隔符的行

时间:2017-03-20 06:00:32

标签: java

  

读取一行文字。一条线被认为是换行(' \ n'),回车(' \ r')或回车后紧接着换行符中的任何一条终止------ javadoc 1.8

然后我有一个这样的文本文件:

the first line
the second line

注意: seond line的最后一个字符是' e'也就是说不存在回车。

然后这是我的演示代码。

public void process() throws IOException{
    BufferedReader br = new BufferedReader(new FileReader("demo.txt"));
    String line;
    while((line=br.readLine())!=null){
        System.out.println(line);
    }
    br.close();
}

实际输出:

 the first line
 the second line

那么我的问题是为什么readLine方法可以获得第二行,因为它没有行分隔符(\ n或\ r或\ n \ r \ n)。
我知道存在一个文件结尾(EOF),但似乎javadoc并没有明确告诉 EOF 也是行分隔符。

如果我使用Scanner而不是BufferedReader,代码如下:

public void testScan() throws IOException{
    Scanner scan = new Scanner(new FileInputStream("demo.txt"));
    String line;
    while((line=scan.nextLine())!=null){
        System.out.println(line);
    }
    scan.close();
}

然后输出将是:

the first line
the second line
Exception in thread "main" java.util.NoSuchElementException: No line found
    at java.util.Scanner.nextLine(Scanner.java:1540)
    at com.demo.Demo.testScan(Demo.java:39)
    at com.demo.Demo.main(Demo.java:49)

2 个答案:

答案 0 :(得分:10)

因为它以这种方式编程。

真的,这是该方法的用户想要的。如果最后一行在结尾处缺少行分隔符,则它将一直读到EOF,以便不会丢失任何数据。由于缺少行分隔符,您不想丢失整行。

实际上所有类似的功能都以相同的方式工作。例如,如果您正在查看C库中的fgets()函数,它也会以这种方式工作。 Python中的f.readline()也是如此。

编辑:扫描程序也以类似的方式工作,但区别在于扫描程序抛出异常,而BufferedReader在读取所有行时返回null。

答案 1 :(得分:10)

  

似乎javadoc不告诉EOF也是行分隔符   明确。

我认为您将行分隔符行终止符混淆。

线条分隔符只是将线条彼此分开。给定行分隔符;和输入one;two;three,您就会得到行onetwothree。但是,如果相同的字符和输入但;是行终止符,则您会获得行onetwo,因为最后一行未终止。

实际上,这意味着如果EOF确实是一个行分隔符,那么您将获得额外的数据。由于EOF在技术上不是一个字符,而是文件已经结束的条件,因此将EOF作为行分隔符会产生严重后果。

但是,鉴于javadoc

  

读取一行文字。一条线被认为是任何一条线终止的   换行(' \ n'),回车(' \ r')或回车   然后立即换行。

我认为术语也被滥用了。要么javadoc应该讨论分离而不是终止,它应该提到EOF作为终止该行的条件之一,或者实现不应该将最后一个作为单独的行处理。

来自Wikipedia

  

两种查看换行符的方法都是自洽的   换行要么是单独的行,要么是终止行。如果一个   newline被认为是一个分隔符,之后就没有换行了   文件的最后一行。有些程序在处理上一个程序时遇到问   文件的行,如果它没有被换行符终止。在另一   希望将换行用作分隔符的程序   将最终换行符解释为开始新(空)行。反过来,   如果换行符被视为终止符,则所有文本行都包括   预计最后一个换行符将被终止。如果是最终的   文本文件中的字符序列不是换行符,最后一行   该文件可能被视为不正确或不完整的文本行,   或者该文件可能被视为被不正当地截断。

所以似乎readLine()混淆了这些。

IMO readLine() javadoc应该说:

  

一行被视为在文件末尾终止或   通过任何一个换行   (' \ n'),回车(' \ r'),或者是回车符号   立即用换行符。

或更复杂的表达,类似于Scanner.nextLine() says

  

此方法返回[..]当前行,不包括任何行   最后的分隔符

另外,当文件末尾是唯一的输入时,它将返回null