2012-02-29 19 views
13

Tengo un comportamiento extraño con Scanner. Funcionará con un conjunto particular de archivos que estoy usando cuando utilizo el constructor Scanner(FileInputStream), pero no con el constructor Scanner(File).Java Scanner (archivo) portándose mal, pero Scanner (FIleInputStream) siempre funciona con el mismo archivo

Caso 1: Scanner(File)

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

Resultado: ninguna salida

Caso 2: Scanner(FileInputStream)

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

Resultado: salidas de contenido el archivo en la consola.

El archivo de entrada es un archivo java que contiene una sola clase.

me doble registrado mediante programación (en Java) que:

  • el archivo existe,
  • es legible,
  • y tiene un tamaño de archivo que no sea cero.

Por lo general, Scanner(File) funciona para mí en este caso, no estoy seguro de por qué no lo hace ahora.

+0

¿Qué contiene el archivo? – Dan675

+0

¿Y es ese el único código, o hay otras cosas sucediendo alrededor de todo eso? Este fragmento parece incompleto, ya que habría al menos algún tipo de manejo de excepciones. ¿Podría proporcionarnos todo el código? – haylem

+0

Pregunta interesante. Por favor, publique su código real y un pastebin con su archivo. Además, ¿cuál es el resultado de 'Charset.defaultCharset()' en su sistema? – Perception

Respuesta

7

hasNextLine() llama findWithinHorizon() que a su vez llama a findPatternInBuffer(), buscando a la altura de un patrón de carácter terminador de línea definido como .*(\r\n|[\n\r\u2028\u2029\u0085])|.+$

Lo extraño es que con las dos maneras de construir un escáner (con FileInputStream oa través de archivos), declaraciones de findPatternInBuffer una coincidencia positiva si el archivo contiene (independientemente del tamaño del archivo) por ejemplo el terminador de línea 0x0A; pero en el caso de que el archivo contenga un carácter fuera de ascii (es decir,> = 7f), el uso de FileInputStream devuelve verdadero mientras usa el archivo devuelve falso.

caso de prueba muy sencilla:

crear un archivo que contiene solo char "un"

# hexedit file  
00000000 61 0A            a. 

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

Ahora edita el archivo con hexedit a:

# hexedit file 
00000000 61 0A 80            a.. 

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

en el código java prueba no hay nada más que lo que ya está en la pregunta:

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, resulta que se trata de un problema de juego de caracteres. En los hechos, el cambio de la prueba a:

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

obtenemos:

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

Interesante. Cuando se observan los constructores 'Scanner', todos parecen estar asumiendo el juego de caracteres predeterminado si no se especifica, sin embargo, hay una diferencia en el tiempo de ejecución como usted señala. usado internamente, ¿quizás forzar uno diferente, un nivel más profundo? Me pregunto ... Trataré de verificar cuando tenga la oportunidad. – haylem

5

De su análisis de la Oracle/Sun JDK's 1.6.0_23 implementation of Scanner, la Scanner(File) constructor invoca un FileInputStream, que es meant for raw binary data.

Esto apunta a una diferencia en la técnica de búfer y análisis utilizada al invocar un constructor u otro, lo que afectará directamente a su código en la llamada al hasNextLine().

Scanner(InputStream) utiliza un InputStreamReader mientras Scanner(File) utiliza un InputStream pasado a una ByteChannel (y, probablemente, lee el archivo completo en un solo salto, avanzando así el cursor, en su caso).

+0

información muy interesante, gracias por compartir –

+2

El contrato para Java (Archivo) y Java (FileInputStream) dice lo mismo, por lo que deben producir el mismo comportamiento desde el punto de vista del usuario API. He utilizado Java (Archivo) antes sin este problema. – kashiko

+0

Yanick: Gracias, esta es una pregunta interesante. Pero parece haber más en esto ... (Aún así, las cosas que puedes extraer del código del JDK a veces ... Tuve un momento "¿Qué?" Cuando noté que hay múltiples definiciones de 'ArrayList', por ejemplo (y no, no son exactamente idénticos). – haylem

Cuestiones relacionadas