Java Scanner(文件)行为不当,但Scanner(FIleInputStream)始终使用相同的文件

我对Scanner有一种奇怪的行为。 当我使用Scanner(FileInputStream)构造函数时,它将与我正在使用的一组特定文件一起使用,但它不会与Scanner(File)构造函数一起使用。

案例1: Scanner(File)

 Scanner s = new Scanner(new File("file")); while(s.hasNextLine()) { System.out.println(s.nextLine()); } 

结果:没有输出

案例2: Scanner(FileInputStream)

 Scanner s = new Scanner(new FileInputStream(new File("file"))); while(s.hasNextLine()) { System.out.println(s.nextLine()); } 

结果:文件内容输出到控制台。

输入文件是包含单个类的java文件。

我以编程方式(在Java中)仔细检查:

  • 该文件存在,
  • 是可读的,
  • 并且具有非零文件大小。

在这种情况下, Scanner(File)通常适用于我,我不知道为什么现在没有。

hasNextLine()调用findWithinHorizo​​n()来调用findPatternInBuffer() ,搜索匹配的行终止符字符模式定义为.*(\r\n|[\n\r\u2028\u2029\u0085])|.+$

奇怪的是,通过两种方式构建Scanner(使用FileInputStream或通过File),如果文件包含(独立于文件大小),例如0x0A行终止符,则findPatternInBuffer返回正匹配; 但是如果文件包含ascii之外的字符(即> = 7f),则使用File返回false时,使用FileInputStream返回true。

非常简单的测试用例:

创建一个只包含char“a”的文件

 # hexedit file 00000000 61 0A a. # java Test.java using File: true using FileInputStream: true 

现在使用hexedit编辑文件:

 # hexedit file 00000000 61 0A 80 a.. # java Test.java using File: false using FileInputStream: true 

在测试java代码中,除了问题中已有的内容之外别无其他:

 import java.io.*; import java.lang.*; import java.util.*; public class Test { public static void main(String[] args) { try { File file1 = new File("file"); Scanner s1 = new Scanner(file1); System.out.println("using File: "+s1.hasNextLine()); File file2 = new File("file"); Scanner s2 = new Scanner(new FileInputStream(file2)); System.out.println("using FileInputStream: "+s2.hasNextLine()); } catch (IOException e) { e.printStackTrace(); } } } 

所以,事实certificate这是一个charset问题。 事实上,将测试更改为:

  Scanner s1 = new Scanner(file1, "latin1"); 

我们得到:

 # java Test using File: true using FileInputStream: true 

通过查看Oracle / Sun JDK的1.6.0_23 Scanner实现 , Scanner(File)构造函数调用FileInputStream ,它适用于原始二进制数据

这指出了在调用一个或另一个构造函数时使用的缓冲和解析技术的不同,这将直接影响对hasNextLine()的调用。

Scanner(InputStream)使用InputStreamReaderScanner(File)使用传递给ByteChannelInputStream (并且可能在一次跳转中读取整个文件,因此在您的情况下推进光标)。