2010-05-08 7 views
19

Cuando ejecuto una aplicación Java que debería leer desde un archivo en Eclipse, obtengo un java.io.FileNotFoundException, aunque el archivo esté en el directorio correcto. Puedo compilar y ejecutar la aplicación desde la línea de comandos sin problemas; el problema solo ocurre en Eclipse, con más de un proyecto y aplicación. ¿Hay alguna configuración que deba cambiar en las configuraciones de ejecución o las rutas de compilación para que encuentre el archivo correctamente?Java no puede encontrar el archivo cuando se ejecuta a través de Eclipse

+1

sin ver su código, no podemos decirle lo que podría estar pasando –

Respuesta

28

El problema es más probable que la aplicación está utilizando una ruta relativa. Como dice @BalusC, los nombres de ruta relativos pueden ser problemáticos. Pero OMI, va demasiado lejos cuando dice "[y] o debería nunca usar rutas relativas en las cosas java.io".

Cuando una aplicación abre un archivo usando (por ejemplo) el constructor FileInputStream(File), rutas relativas se resuelven en relación con el "directorio actual" en un proceso descrito como sigue en el Javadoc para File.getAbsolutePath().

[...] De lo contrario, este nombre de ruta se resuelve de forma dependiente del sistema. En los sistemas UNIX, una ruta de acceso relativa se hace absoluta resolviéndola contra el directorio de usuario actual. En sistemas Microsoft Windows, un nombre de ruta relativo se hace absoluto resolviéndolo contra el directorio actual de la unidad nombrada por el nombre de ruta, si existe; si no, se resuelve contra el directorio de usuario actual.

De manera inmediata, vemos que la noción de "directorio actual" tiene diferentes matices en las plataformas Windows y UNIX. El segundo problema es que en Java puro no se puede descubrir definitivamente cuál es el directorio actual, y ciertamente no se puede cambiar para la JVM actual utilizando Java puro. (Cuando se inicia JVM, la propiedad del sistema "user.dir" se establece en el directorio actual, pero no hay nada que impida que una aplicación cambie la propiedad, por lo que no puede confiar completamente en ella. Además, cambiar "user.dir" solo cambia la forma en que se resuelve la ruta vacía, no las rutas relativas en general.)

¿Qué debe hacer al respecto?

  • Una opción es utilizar nombres de ruta absolutos para referirse a los archivos. Esto es confiable en (casi) todos los casos, pero el uso de rutas absolutas puede ser problemático si el usuario debe ingresar la ruta, o si necesita evitar las rutas de acceso absolutas (o configuradas).

  • Una segunda opción es usar rutas de acceso relativas de clase y localizar archivos relativos al directorio de instalación de la aplicación. Esto funciona si eso es lo que debe hacer, pero presenta un problema si necesita pasar un File a algún método de biblioteca. Tampoco ayuda si está tratando de encontrar las preferencias de la aplicación del usuario. (En general, poner las preferencias del usuario en el directorio de instalación es un error ...)

  • Una tercera opción es nombrar un archivo relativo a un directorio absoluto que se obtiene de otro lugar; p.ej. new File(System.getProperty("home.dir"), "foo/bar");.

  • La última opción es usar nombres de ruta relativos, y asumir que el usuario conoce cuál es el directorio actual. Para muchas aplicaciones que el usuario ejecuta desde la línea de comandos, esta es la solución correcta.

En el caso particular de Eclipse, hay una solución simple. Vaya a la "configuración de ejecución" que está utilizando para iniciar su aplicación, abra la pestaña "Argumentos" y haga clic en el botón de opción "Otro". Luego ingrese una ruta de acceso absoluta como el directorio de trabajo para la aplicación iniciada. Cuando se inicia la JVM secundaria, tendrá el directorio de trabajo especificado como su directorio actual.

+0

¡Gracias por su ayuda! – derekerdmann

+0

Tuve un problema con mi aplicación lanzada desde eclipse que no podía leer algún archivo de propiedades que estaba en la raíz de mi proyecto.Después de intentar configurar el directorio de trabajo en la configuración de ejecución en $ {workspace_loc}/myproject/bin ¡funcionó !. – Krishnaraj

+0

@Krishnaraj - Eso es lo que dije en el último párrafo de mi respuesta :-) –

6

Cuando se crea una aplicación Java en Eclipse predeterminado, se obtiene esta estructura de directorios:

./ProjectName/ - directorio
./ProjectName/bin/ root - directorio de salida, que contiene .class
archivos ./ProjectName/src/ - directorio de origen, que contiene los archivos .java

Si sus peticiones de aplicaciones "./data.txt" va a buscar lo relativo al directorio raíz. Este es el "directorio de trabajo" y se puede configurar en la pestaña de argumentos según la respuesta de Martin anterior.

¿Dices que funciona desde la línea de comandos? Esto es probable porque estás dentro de las carpetas bin o src cuando ejecutas el binario java. El directorio de trabajo en este caso es el directorio en el que se encuentra actualmente el símbolo del sistema. Si, por ejemplo, entra en el directorio/src /, digamos javac *.java y luego ejecuta los archivos desde allí, buscará "./data.txt" en el directorio/src /. Si ingresa al directorio/bin/y ejecuta su aplicación desde allí, buscará el archivo relativo al directorio/bin /.

+0

Gracias por su ayuda. Los archivos de texto que necesito existen en el directorio/bin /, así que ese no parece ser el problema. Jugaré caminos relativos y veré qué puedo obtener. – derekerdmann

2

Usted debe nunca usar las rutas relativas en java.io cosas. La ruta se volvería dependiente del directorio de trabajo actual, que depende de la forma en que comenzó la aplicación y, por lo tanto, no es per se en todos los entornos. Esto es incontrolable desde el interior de la aplicación Java. ¡Problemas de portabilidad! Siempre use rutas absolutas. Por ejemplo, por ej. c:/path/to/file.ext o /path/to/file.ext (con la barra diagonal) para UNIX y consortes (o incluso Windows cuando la letra del disco es irrelevante).

Siempre que desee enviar algunos archivos junto con su aplicación, una práctica común es colocarlos también en el classpath . De esta manera, puede usar ClassLoader#getResource() para obtener su ubicación. Devuelve un URL. Puede usar URL#toURI() o URL#getPath() y pasarlo al constructor de java.io.File y luego usarlo de la forma habitual.

En su proyecto Eclipse, la carpeta src (donde va su fuente Java) es básicamente la raíz de la ruta de clase. Además, por supuesto, también cubre todos los demás proyectos y carpetas (externas) que se toman en la Ruta de compilación del proyecto.

Suponiendo que usted ha colocado el archivo en particular en el raíz de la ruta de clases:

ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 
URL url = classLoader.getResource("file.ext"); 
File file = new File(url.getPath()); 
FileInputStream input = new FileInputStream(file); 
// ... 

Incluso puede utilizar ClassLoader#getResourceAsStream() para obtener directamente una InputStream:

ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 
InputStream input = classLoader.getResourceAsStream("file.ext"); 
// ... 

Si se coloca dentro de un paquete, entonces usted puede simplemente usar las rutas habituales:

URL url = classLoader.getResource("com/example/file.ext"); 
// ... 

o

InputStream input = classLoader.getResourceAsStream("com/example/file.ext"); 
// ... 
+0

una aplicación de línea de comandos que no es una GUI puede razonablemente diseñarse para usar nombres de ruta relativos. La advertencia es que el usuario debe comprender el concepto de "el directorio actual", y el programador debe comprender cómo se correlaciona con el comportamiento de las bibliotecas de Java IO. –

+0

@Stephen: Seguramente es posible, solo tendrás que lidiar con rutas relativas, pero no es recomendable. Tomar ventaja del classpath lo hace más robusto. – BalusC

+0

depende de lo que la aplicación esté haciendo. Por ejemplo, si está manipulando archivos suministrados por el usuario, entonces el enfoque de classpath tiene poco sentido. –

1

Suponiendo que el usuario no ingrese la ruta completa al archivo y escriba algo como "myfilenameonly". File file = new File(".", args[0]) es necesario en este caso para localizar el archivo (prestando atención al primer argumento pasado).

Todas las plataformas: File.getParent() no devuelve el directorio padre, debe devolver ".." o el nombre del directorio padre en una manera específica sistema de archivos.

Si crea el archivo "myfilenameonly", sin especificar la ruta completa al directorio en el que se encuentra, el File.getParent(), por ejemplo, devolverá un valor nulo.

Véase además: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=1228537

2

que estaba teniendo un problema similar, coloqué mis archivos en una carpeta cobolcopybooks nombrados dentro de la carpeta src y trató de acceder a ellos dentro de mi proyecto utilizando classloader.getResource ("cobolcopybooks/demostud. cob ") pero obtenía una excepción de puntero nulo, lo intenté varias veces limpiando y construyendo los espacios de trabajo después de varios intentos fallidos. Me di cuenta de que no estaba refrescando el proyecto para permitir que los archivos se construyeran junto con el proyecto. Es decir, estos archivos deben estar visibles junto con otros archivos de clase, ya que en tiempo de ejecución, el directorio raíz será el directorio bin y allí buscará esos archivos.

8

Otra opción es simplemente averiguar a qué directorio apunta la "ruta actual" en su entorno, sea lo que sea. Una vez que lo descubras, puedes elegir tu solución desde allí. Tal vez sea utilizar una ruta relativa adecuada a la ubicación de su archivo o reubicar el archivo.

File testFile = new File(""); 
    String currentPath = testFile.getAbsolutePath(); 
    System.out.println("current path is: " + currentPath); 
+1

Esto no es ideal en el código de envío, pero definitivamente es útil como código de depuración para ver lo que su aplicación piensa que está sucediendo. – Steve

Cuestiones relacionadas