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

时间:2012-02-29 01:53:00

标签: java java.util.scanner java-io

我对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)适用于我,我不知道为什么现在没有。

2 个答案:

答案 0 :(得分:7)

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

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

非常简单的测试用例:

创建一个只包含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();
        }
    }
}

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

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

我们得到:

# java Test 
using File: true
using FileInputStream: true

答案 1 :(得分:5)

通过查看Oracle/Sun JDK's 1.6.0_23 implementation of ScannerScanner(File)构造函数会调用FileInputStream,即 meant for raw binary data

这指出在调用一个或另一个构造函数时使用的缓冲和解析技术的差异,这将直接影响到hasNextLine()调用时的代码。

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