Java Scanner(File) 行为异常,但 Scanner(FIleInputStream) 始终适用于同一文件案例1:Scanner(File) 案例2:Scanner(FileInputStream)

2022-09-04 03:36:45

我在使用扫描仪时有奇怪的行为。当我使用构造函数时,它将与我正在使用的一组特定文件一起使用,但它不会与构造函数一起使用。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)


答案 1

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

奇怪的是,使用两种构造扫描程序的方法(使用FileInputStream或通过File),如果文件包含(独立于文件大小)例如0x0A行终止符,findPatternInBuffer将返回正匹配项;但是如果文件包含一个来自 ascii 的字符(即 >= 7f),则使用 FileInputStream 返回 true,而使用 File 返回 false。

非常简单的测试用例:

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

# hexedit file     
00000000   61 0A                                                a.

# java Test.java
using File: true
using FileInputStream: true

现在使用十六进制编辑文件以:

# 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();
        }
    }
}

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

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

我们得到:

# java Test 
using File: true
using FileInputStream: true

答案 2

通过查看Oracle / Sun JDK的1.6.0_23 Scanner(File)构造函数调用FileInputStream,该配置文件用于原始二进制数据

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

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


推荐