Подтвердить что ты не робот

Сканер Java (File) неправильно работает, но Scanner (FIleInputStream) всегда работает с одним и тем же файлом

У меня странное поведение со Сканером. Он будет работать с определенным набором файлов, которые я использую, когда я использую конструктор 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) работает для меня в этом случае, я не уверен, почему это не так.

4b9b3361

Ответ 1

hasNextLine() вызывает findWithinHorizon(), который в вызывает вызовы findPatternInBuffer(), поиск совпадений для символа символа символа линии, определенного как .*(\r\n|[\n\r\u2028\u2029\u0085])|.+$

Странно то, что с помощью обоих способов построения сканера (с FileInputStream или через File) findPatternInBuffer возвращает положительное соответствие, если файл содержит (независимо от размера файла), например, терминатор линии 0x0A; но в случае, если файл содержит символ из 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();
        }
    }
}

SO, получается, что это проблема с кодировкой. В действительности, изменение теста на:

 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) использует InputStream, переданный в ByteChannel (и, вероятно, читает весь файл за один прыжок, тем самым продвигая курсор в вашем случае).