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

nai*_*fei 9 java

读一行文字.一条线被认为是由换行符('\n'),回车符('\ r')或回车符后面的任何一个终止,然后是换行符.------ javadoc 1.8

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

the first line
the second line
Run Code Online (Sandbox Code Playgroud)

注意: 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();
}
Run Code Online (Sandbox Code Playgroud)

实际输出:

 the first line
 the second line
Run Code Online (Sandbox Code Playgroud)

那么我的问题是为什么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();
}
Run Code Online (Sandbox Code Playgroud)

然后输出将是:

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)
Run Code Online (Sandbox Code Playgroud)

juh*_*ist 10

因为它以这种方式编程.

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

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

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


eis*_*eis 10

似乎javadoc没有告诉EOF也是明确的行分隔符.

我认为你将行分隔符行终止混淆了.

行分隔符只是将行彼此分开.给定一个行分隔符;和输入one;two;three,你会得到行one,twothree.但是,给定相同的字符和输入但是;作为行终止符,您将获得行one,two因为最后一行不会终止.

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

但是,鉴于javadoc:

读一行文字.一条线被认为是由换行符('\n'),回车符('\ r')或回车符中的任何一个终止,后面紧跟换行符.

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

来自维基百科:

查看换行符的两种方法,即两者都是自洽的,换行符要么是单独的行,要么是终止行.如果换行符被视为分隔符,则在文件的最后一行之后将不会有换行符.如果某个程序没有被换行符终止,则某些程序在处理文件的最后一行时会遇到问题.另一方面,期望将换行用作分隔符的程序会将最终换行符解释为启动新(空)行.相反,如果换行符被视为终止符,则包含最后一行的所有文本行都应该由换行符终止.如果文本文件中的最后一个字符序列不是换行符,则该文件的最后一行可能被认为是不正确或不完整的文本行,或者该文件可能被视为被不正确地截断.

所以看起来似乎readLine()已经混淆了.

IMO readLine()javadoc应该说:

一行被认为是在文件末尾或换行符('\n'),回车符('\ r')或回车符后面的任何一行终止.

或者更复杂的表达,类似于Scanner.nextLine()所说的:

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

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