2012-02-29 7 views
13

Sto avendo un comportamento strano con Scanner. Funzionerà con un particolare set di file che sto usando quando uso il costruttore Scanner(FileInputStream), ma non con il costruttore Scanner(File).Analizzatore anomalo di Java (File), ma Scanner (FIleInputStream) funziona sempre con lo stesso file

Caso 1: Scanner(File)

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

Risultato: nessuna uscita

Caso 2: Scanner(FileInputStream)

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

Risultato: le uscite di contenuti il file per la console.

Il file di input è un file java che contiene una singola classe.

Ho ricontrollato di programmazione (in Java) che:

  • il file esiste,
  • è leggibile,
  • e ha uno spazio diverso da zero.

Tipicamente Scanner(File) funziona per me in questo caso, non sono sicuro del motivo per cui non lo fa ora.

+0

Che cosa contiene il file? – Dan675

+0

Ed è l'unico codice, o ci sono altre cose che accadono intorno a tutto questo? Questo frammento di codice sembra incompleto, in quanto si verificheranno almeno alcune eccezioni. Potresti fornirci l'intero codice? – haylem

+0

Interessante domanda. Per favore pubblica il tuo codice e un pastebin con il tuo file. Inoltre, qual è l'output di 'Charset.defaultCharset()' sul tuo sistema? – Perception

risposta

7

hasNextLine() chiamate findWithinHorizon() che a sua volta chiama findPatternInBuffer(), alla ricerca di una corrispondenza per un modello di carattere terminatore di linea definita come .*(\r\n|[\n\r\u2028\u2029\u0085])|.+$

cosa strana è che con entrambi i modi di costruire uno scanner (con FileInputStream o tramite File), i rendimenti findPatternInBuffer una corrispondenza positiva se il file contiene (indipendentemente dalla dimensione del file) ad esempio il terminatore di riga 0x0A; ma nel caso in cui il file contenga un carattere fuori da ascii (cioè> = 7f), l'uso di FileInputStream restituisce true durante l'utilizzo di File restituisce false.

Molto semplice caso di test:

creare un file che contiene solo char "a"

# hexedit file  
00000000 61 0A            a. 

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

ora modificare il file con hexedit a:

# hexedit file 
00000000 61 0A 80            a.. 

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

nel codice di test Java non c'è nient'altro che quello che già nella domanda:

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

Quindi, si tratta di un problema di charset. In fatti, la modifica del test per:

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

otteniamo:

# java Test 
using File: true 
using FileInputStream: true 
+0

Interessante: quando si osservano i controstati di 'Scanner', sembra che tutti stiano assumendo il set di caratteri predefinito se non specificato, eppure c'è una differenza in fase di esecuzione come si fa notare. Forse il canale usato internamente forse forza uno diverso, un livello più profondo? Mi chiedo ... Proverò a controllare quando avrò una possibilità. – haylem

5

Guardando la Oracle/Sun JDK's 1.6.0_23 implementation of Scanner, il costruttore Scanner(File) invoca un FileInputStream, che è meant for raw binary data.

Questo fa riferimento a una differenza nella tecnica di buffering e parsing utilizzata quando si richiama un costruttore o un altro, che avrà un impatto diretto sul codice sulla chiamata a hasNextLine().

Scanner(InputStream) utilizza un InputStreamReader mentre Scanner(File) utilizza un InputStream passato a un ByteChannel (e, probabilmente, si legge l'intero file in un unico salto, quindi per l'avanzamento del cursore, nel tuo caso).

+0

informazioni molto interessanti, grazie per aver condiviso –

+2

Il contratto per Java (File) e Java (FileInputStream) leggeva lo stesso, quindi dovevano produrre lo stesso comportamento dal punto di vista dell'utente dell'API. Ho usato Java (File) prima senza questo problema. – kashiko

+0

Yanick: Grazie, questa è una domanda interessante. Ma sembra che ci sia di più ... (Ancora, le cose che puoi ricavare dal codice JDK qualche volta ... Hanno avuto un momento "What ??" quando ho notato che ci sono più definizioni di 'ArrayList', ad esempio (e no, non sono esattamente identici.) – haylem

Problemi correlati