通过Eclipse运行时,Java无法找到文件
当我运行应该从Eclipse中的文件读取的Java应用程序时,我得到一个java.io.FileNotFoundException
,即使该文件位于正确的目录中。 我可以从命令行编译并运行应用程序就好了; 问题只出现在Eclipse中,有多个项目和应用程序。 是否需要在运行配置或构建路径中更改设置以使其正确查找文件?
问题很可能是您的应用程序使用相对路径名。 正如@BalusC所说,相对路径名可能会有问题。 但IMO,当他说“你永远不应该在java.io的东西中使用相对路径”时,他走得太远了。
当应用程序使用(例如) FileInputStream(File)
构造函数打开文件时,相对于“当前目录”,相对于“当前目录”,在File.getAbsolutePath()
的javadoc中描述的过程中解析相对路径名。
[…]否则,此路径名将以系统相关的方式解析。 在UNIX系统上,通过将相对路径名解析为当前用户目录,使其成为绝对路径名。 在Microsoft Windows系统上,通过将路径名解析为路径名所指定的驱动器的当前目录(如果有),使相对路径名成为绝对路径名。 如果没有,则针对当前用户目录解析。
所以我们立即看到“当前目录”的概念在Windows和UNIX平台上有不同的细微差别。 第二个问题是,在纯Java中,您无法明确地找出当前目录是什么,并且您当然无法使用纯Java为当前JVM更改它。 (当JVM启动时,“user.dir”系统属性被设置为当前目录,但没有任何东西阻止应用程序更改属性,因此您不能完全依赖它。此外,更改“user.dir”只会更改解决空路径的方式,而不是一般的相对路径。)
那么你应该怎么做呢?
-
一种选择是使用绝对路径名来引用文件。 这在(几乎)所有情况下都是可靠的,但如果用户必须输入路径名,或者如果您需要避免硬连线(或配置)的绝对路径名,则使用绝对路径名可能会有问题。
-
第二种选择是使用类路径相对路径名并找到相对于应用程序安装目录的文件。 如果您需要这样做,这可以工作,但如果您需要将
File
传递给某个库方法,则会出现问题。 如果您尝试查找用户的应用程序首选项,它也无济于事。 (通常,将用户首选项放入安装目录是错误的……) -
第三个选项是相对于从其他地方获得的某个绝对目录命名文件; 例如
new File(System.getProperty("home.dir"), "foo/bar");
。 -
最后一个选项是使用相对路径名,并假设用户知道当前目录是什么。 对于用户从命令行运行的许多应用程序,这是正确的解决方案。
在Eclipse的特定情况下,有一个简单的解决方案。 转到用于启动应用程序的“运行配置”,打开“参数”选项卡,然后单击“其他”单选按钮。 然后输入绝对路径名作为已启动应用程序的工作目录。 启动子JVM时,它将指定的工作目录作为其当前目录。
另一个选择是简单地弄清楚“当前路径”指向您环境中的目录 – 无论是什么。 一旦你弄清楚,你可以从那里选择你的解决方案。 也许这是使用适当的相对路径到您的文件的位置或重新定位文件。
File testFile = new File(""); String currentPath = testFile.getAbsolutePath(); System.out.println("current path is: " + currentPath);
在Eclipse中创建默认Java应用程序时,您将获得以下目录结构:
./ProjectName/ – 根目录
./ProjectName/bin/ – 输出目录,包含.class文件
./ProjectName/src/ – 源目录,包含.java文件
如果您的应用程序请求“./data.txt”,它将相对于根目录搜索它。 这是“工作目录”,可以根据Martin上面的回复在参数选项卡中进行配置。
你说它可以从命令行工作吗? 这可能是因为您在运行java二进制文件时位于bin或src文件夹中。 在这种情况下,工作目录是命令提示符当前所在的目录。 例如,如果你进入/ src /目录,说javac *.java
然后从那里运行文件,它将在/ src /目录中搜索“./data.txt”。 如果你进入/ bin /目录并从那里运行你的应用程序,它将查找相对于/ bin /目录的文件。
你永远不应该在java.io
使用相对路径。 该路径将依赖于当前工作目录,这取决于您启动应用程序的方式,因此在所有环境中本身并不相同。 这在Java应用程序内部是无法控制的。 便携性问题! 始终使用绝对路径。 因此,例如c:/path/to/file.ext
或/path/to/file.ext
(带有前导斜杠)用于UNIX和consorts(当磁盘字母不相关时甚至是Windows)。
每当您想要将某些文件与应用程序一起发送时,通常的做法是将它们放在类路径中。 这样你就可以使用ClassLoader#getResource()
来获取它的位置。 它返回一个URL
。 您可以使用URL#toURI()
或URL#getPath()
并将其传递给java.io.File
构造函数,然后以通常的方式进一步使用它。
在Eclipse项目中, src
文件夹(Java源代码所在的位置)基本上是类路径的根。 此外,它当然还涵盖了项目的构建路径中的所有其他项目和(外部)文件夹。
假设您已将特定文件放在类路径的根目录中:
ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); URL url = classLoader.getResource("file.ext"); File file = new File(url.getPath()); FileInputStream input = new FileInputStream(file); // ...
您甚至可以使用ClassLoader#getResourceAsStream()
直接获取InputStream
:
ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); InputStream input = classLoader.getResourceAsStream("file.ext"); // ...
如果它放在一个包中,那么你可以使用通常的路径名:
URL url = classLoader.getResource("com/example/file.ext"); // ...
要么
InputStream input = classLoader.getResourceAsStream("com/example/file.ext"); // ...
我遇到了类似的问题,我将文件放在src文件夹中名为cobolcopybooks的文件夹中,并尝试使用classloader.getResource(“cobolcopybooks / demostud.cob”)在我的项目中访问它们,但我得到空指针exception,我经过多次尝试失败后,我通过清理和构建工作区尝试了几次,我意识到我没有刷新项目以允许文件与项目一起构建。 即这些文件应该与其他类文件一起可见,因为在运行时根目录将是bin目录,并且它在那里搜索那些文件。
假设用户没有输入文件的完整文件路径并输入类似“myfilenameonly”的内容。 File file = new File(".", args[0])
在这种情况下是必要的,以找到文件(注意传递的第一个参数)。
所有平台: File.getParent()
不返回父目录,它应以文件系统特定的方式返回“..”或父目录的名称。
如果创建文件“myfilenameonly”而未指定其所在目录的完整路径,则File.getParent()
将返回null。
进一步了解: http : //bugs.sun.com/bugdatabase/view_bug.do?video_id = 1228537