2010-02-16 8 views
9

JRE 6, en Windows XP.Java: Incoherencias de File.exists() al establecer "user.dir"

La duplicación de dos objetos de archivo con diferentes constructores genera resultados incoherentes en el método File.exists().

responsabilidad: el código de abajo es un resumen, no el código real. No creo que esto sea un problema de File.separator en absoluto. Primero pedí reacciones tempranas, por si me perdía un tema bien entendido. Parece que restablecer la propiedad del sistema user.dir es una de las causas de este problema. El código a continuación ahora es reproducible y utilizable tal cual. Puede copiar/pegar la clase Java y probarla, debe comportarse de manera consistente con lo que he enumerado como resultados.

Configuración:

Crear la arquitectura carpeta C:\toto\tmp\sub.

Inicie la siguiente clase desde cualquier carpeta que no contenga una arquitectura de subcarpeta tmp/sub.

Código:

public class TestFileExists { 

    public static void main(String[] args) { 

     System.setProperty("user.dir", "C:\\toto\\"); 

     File root = new File("tmp"); 

     File sub_a = new File(root, "sub"); 

     File sub_b = new File(root.getAbsolutePath()+"/sub"); 

     System.out.println("sub_a path ? "+sub_a.getAbsolutePath()); 
     System.out.println("sub_a exists ? "+sub_a.exists()); 
     System.out.println("sub_b path ? "+sub_b.getAbsolutePath()); 
     System.out.println("sub_b exists ? "+sub_b.exists()); 
     System.out.println("Path equals ? "+ (sub_a.getAbsolutePath().equals(sub_b.getAbsolutePath()))); 
     System.out.println("Obj equals ? "+ (sub_a.equals(sub_b))); 

    } 

} 

Resultado:

sub_a path ? C:\toto\tmp\sub 
sub_a exists ? false 
sub_b path ? C:\toto\tmp\sub 
sub_b exists ? true 
Path equals ? true 
Obj equals ? false 

No entiendo la línea sub_a exists ? false, y el resultado no es consistente de una máquina a otra, ni con el raíz ruta inicial y el resultado ahora es coherente con de máquina a máquina.

Ahora si, vuelva a ejecutar la clase llamando Java desde la línea de comandos, desde una carpeta, que contiene una arquitectura subcarpeta tmp/sub (como si se llama desde D:\, teniendo D:\tmp\sub), recibirá la esperada:

sub_a path ? C:\toto\tmp\sub 
sub_a exists ? true 
sub_b path ? C:\toto\tmp\sub 
sub_b exists ? true 
Path equals ? true 
Obj equals ? false 

Pero la existencia de sub_a es claramente un falso positivo, porque comprueba la existencia de otra carpeta que el descrito por el getAbsolutePath().

por lo que sospecho fuertemente que File.exists() depende de la trayectoria real de ejecución de Java, y que la existencia de archivos no es consistente con la ruta absoluta, y exists() utiliza otro camino que la propiedad del sistema "user.dir" para comprobar el sistema de archivos.

¿Alguna idea de dónde podría venir este problema?

+1

Conjetura salvaje: algunos atributos estropeados en un directorio intermediario que se atraviesa con la ruta absoluta. –

+0

En Windows XP con JDK 1.6.0_16 y Java 1.6.0_18, me hago verdadero, cierto. verdadero Falso. Habiendo dicho eso, mi directorio no tiene espacios, caracteres especiales ni permisos denegados. – Powerlord

+1

Downvoter puede explicar por qué? – glmxndr

Respuesta

9

La configuración user.dir no es compatible. Debe considerarse una propiedad de solo lectura.

Por ejemplo, la evaluación de Bug 4117557 en el desfile de Sun Bug contiene este texto:

"user.dir", que es inicializado durante el inicio de la JVM, debe usarse como una propiedad del sistema informativo /sólo lectura, intente personalizarlo a través de la línea de comando -Duser.dir = xyz terminará en la implementación dependend/comportamiento no especificado.

Si bien este texto trata de establecerlo en la línea de comandos, su configuración a través de setProperty() es igualmente indefinido.

Cuando puede reproducir el problema sin configurando user.dir manualmente, entonces ha encontrado un problema real.

+0

Perfecto, muchas gracias. – glmxndr

+0

La razón por la que esto no funciona no se debe a que no se admite la configuración de user.dir. Se debe a que user.dir se ignora cuando se utilizan rutas de acceso relativas para los archivos, mientras que File.getAbsolutePath() lo tiene en cuenta. Esto significa que el mismo archivo puede hacer referencia a dos ubicaciones, dependiendo de si lo convierte a archivo absoluto o no. Solución: evite utilizar rutas relativas. –

+0

@Roman: Lo siento, pero estás equivocado. Eso es solo un efecto del hecho de que el sistema supone que 'user.dir' nunca cambia por el usuario. 'getAbsolutePath()' está documentado como "resuelto de una manera dependiente del sistema" contra el directorio de usuario actual. Por lo tanto, 'getAbsolutePath()' debe * siempre * devolver la misma ruta exacta a la que se accederá si acaba de utilizar la ruta relativa directamente para acceder a un archivo. ¡Ese es el objetivo de ese método! –

0

En esta línea:

File sub_b = new File(root.getAbsolutePath()+"/sub"); 

Usted debe estar utilizando la constante File.separator (depende del sistema subyacente) en lugar de una barra rígida.

+1

No, lo primero que hace el constructor de archivos es normalizar el formulario, por lo que no debería ser de ayuda. –

+0

No, cometí un error al copiar los resultados. En realidad, es sub_a que se detecta como no existente. – glmxndr

0

Creo que es el separador de directorios, ya que Windows usualmente usa la barra invertida "\" mientras que Linux usa la barra normal "/".

trate de cambiar la línea en:

File sub_b = new File(root.getAbsolutePath() + System.getProperty("file.separator") + "sub"); 
+0

No, cometí un error al copiar los resultados. En realidad, es sub_a que se detecta como no existente. Lo siento de nuevo. – glmxndr

0

Esto puede ser un problema de separador de archivos. En Windows, el separador de archivos estándar es la barra diagonal inversa (\). Cuando crea sub_b, crea un nombre de ruta (como String) que contiene barras diagonales y barras diagonales inversas. El sistema puede confundirse un poco con eso.

+0

No, cometí un error al copiar los resultados. En realidad, es sub_a que se detecta como no existente. Lo siento. Pregunta editada. Lo siento de nuevo. – glmxndr

0

Estos resultados deberían ser determinísticos en todas las máquinas. Permítanme descomponerlo por línea:

System.out.println("sub_a exists ? "+sub_a.exists()); 

Aquí, usted está preguntando si este archivo existe realmente en el sistema de archivos. Esto siempre debería devolver el mismo, suponiendo que el archivo exista.

System.out.println("sub_b exists ? "+sub_b.exists()); 

Lo mismo. Está comprobando para ver si este archivo realmente existe.

System.out.println("Path equals ? "+ (sub_a.getAbsolutePath().equals(sub_b.getAbsolutePath()))); 

Aquí está viendo si el AbsolutePath es el mismo.

System.out.println("Obj equals ? "+ (sub_a.equals(sub_b))); 

Y aquí, estás haciendo una comparación con objeto .equals(), que bajo el capó llamarán a la clase de sistema de archivos para hacer un comparar() de la trayectoria de los dos objetos objetos, no su AbsolutePath.

La probabilidad es que el separador de archivos esté equivocado. Trate de sustituir File.separator en la construcción de sub_b, así:

File sub_b = new File(root.getAbsolutePath()+File.separator+"sub"); 
1

File lata representa un resumen ruta . Crear un File para tmp y uno de la ruta absoluta de tmp no será igual a File objetos aunque sus rutas absolutas son iguales.

No estoy exactamente seguro de un escenario en el que sub_a no exista pero sub_b lo hará, pero dudo que sea un problema de separación. Sospecho que es algo que ver con esta declaración de la javadoc for File(File,String):

cada cadena de ruta se convierte en una vía de acceso abstracta y el niño vía de acceso abstracta se resuelve en contra del padre.

no sé una situación en sistemas de archivos basados ​​en Unix, donde, desde el interior de /full/path/to, existirá ./tmp/sub pero /full/path/to/tmp no lo hará.

Si el problema es coherente entre los sistemas, se puede entender más claramente al eliminar más el estado de cada objeto File en lugar de solo imprimir comparaciones.

+0

Estoy de acuerdo con usted en la pista de no separación. Parece suceder cuando se establece la propiedad 'user.dir'. Actualizaré la pregunta tan pronto como obtenga una comprensión más profunda sobre el contexto de la ejecución. – glmxndr

2

añadir las siguientes líneas a su prueba:

System.out.println("sub_a = " + sub_a); 
System.out.println("sub_b = " + sub_b); 

Conclusiones:

1) sub_a es una ruta relativa y sub_b es absoluta.

2) exists() no utiliza la ruta absoluta

3) establecer la variable de entorno user.dir no cambia el directorio de usuario actual, utilizado por exists()

4) getAbsolutePath utiliza la variable user.dir en lugar de la verdadera directorio de usuario actual! Al menos para Windows (vea Win32FileSystem.getuserPath). ¡Ese es el problema! (¿Error?)

+0

Absolutamente. Sin embargo, parece que no es un error, sino un error del usuario.dir, que no fue concebido para ser modificable durante la ejecución. – glmxndr

Cuestiones relacionadas