Java Scanner (File) работает неправильно, но Scanner (FIleInputStream) всегда работает с одним и тем же файлом - PullRequest
14 голосов
/ 29 февраля 2012

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

7 голосов
/ 29 февраля 2012

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

Странно то, что при обоих способах построения Scanner (с FileInputStream или с помощью File) findPatternInBuffer возвращает положительное совпадение, если файл содержит (независимо от размера файла), например, терминатор строки 0x0A;но в случае, если файл содержит символ вне ascii (то есть> = 7f), использование FileInputStream возвращает true, а при использовании File возвращает false.

Очень простой тестовый случай:

создайте файл, которыйсодержит только символ "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();
        }
    }
}

ТАК, оказывается, это проблема кодировки.Фактически, изменив тест на:

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

, мы получим:

# java Test 
using File: true
using FileInputStream: true
5 голосов
/ 29 февраля 2012

Если взглянуть на реализацию сканера Oracle / Sun JDK 1.6.0_23, то конструктор Scanner(File) вызывает FileInputStream, то есть предназначено для необработанных двоичных данных .

Это указывает на разницу в технике буферизации и разбора, используемой при вызове того или иного конструктора, что напрямую повлияет на ваш код при вызове hasNextLine().

Scanner(InputStream) использует InputStreamReader, в то время как Scanner(File) использует InputStream, переданное ByteChannel (и, вероятно, читает весь файл за один прыжок, перемещая курсор, в вашем случае).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...