当我运行应该从Eclipse中的文件读取的Java应用程序时,即使文件位于正确的目录中,我也会获得java.io.FileNotFoundException
。我可以从命令行编译并运行应用程序就好了;该问题仅发生在Eclipse中,具有多个项目和应用程序。我是否需要在运行配置或构建路径中更改设置以使其正确查找文件?
答案 0 :(得分:29)
问题很可能是您的应用程序使用的是相对路径名。正如@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时,它将指定的工作目录作为其当前目录。
答案 1 :(得分:8)
另一种选择是简单地弄清楚“当前路径”指向您环境中的目录 - 无论是什么。一旦你弄清楚,你可以从那里选择你的解决方案。也许这是使用适当的文件位置相对路径或重新定位文件。
File testFile = new File("");
String currentPath = testFile.getAbsolutePath();
System.out.println("current path is: " + currentPath);
答案 2 :(得分:7)
在Eclipse中创建默认Java应用程序时,您将获得以下目录结构:
./ ProjectName / - 根目录
./ ProjectName / bin / - 输出目录,包含.class文件
./ ProjectName / src / - 源目录,包含.java文件
如果您的应用程序请求“./data.txt”,它将相对于根目录搜索它。这是“工作目录”,可以根据Martin上面的回复在参数选项卡中进行配置。
你说它可以从命令行运行吗?这可能是因为您在运行java二进制文件时位于bin或src文件夹中。在这种情况下,工作目录是命令提示符当前所在的目录。例如,如果你进入/ src /目录,说javac *.java
然后从那里运行文件,它将搜索/ src /目录中的“./data.txt”。如果你进入/ bin /目录并从那里运行你的应用程序,它将查找相对于/ bin /目录的文件。
答案 3 :(得分:2)
你应该从不使用java.io
内容中的相对路径。该路径将依赖于当前工作目录,这取决于您启动应用程序的方式,因此在所有环境中本身并不相同。这在Java应用程序内部是无法控制的。便携性问题!始终使用绝对路径。例如,适用于UNIX和consorts的c:/path/to/file.ext
或/path/to/file.ext
(带有前导斜杠)(当磁盘字母不相关时,甚至是Windows)。
每当您想要将某些文件与应用程序一起发送时,通常的做法是将它们放在类路径中。这样您就可以使用ClassLoader#getResource()
来获取其位置。它返回URL
。您可以使用URL#toURI()
或URL#getPath()
将其传递给java.io.File
的构造函数,然后以通常的方式进一步使用它。
在Eclipse项目中,src
文件夹(Java源代码所在的文件夹)基本上是类路径的根。此外,它当然还涵盖了项目的构建路径中的所有其他项目和(外部)文件夹。
假设您已将特定文件放在类路径的 root 中:
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");
// ...
答案 4 :(得分:2)
我遇到了类似的问题,我将文件放在src文件夹中名为cobolcopybooks的文件夹中,并尝试使用classloader.getResource(“cobolcopybooks / demostud.cob”)在我的项目中访问它们 但我得到空指针异常,我尝试了几次通过几次失败尝试后清理和构建工作区我意识到我没有刷新项目,以允许文件与项目一起构建。即这些文件应该与其他类文件一起可见,因为在运行时根目录将是bin目录,并且它在那里搜索那些文件。
答案 5 :(得分:1)
假设用户没有输入文件的完整文件路径
并输入类似“myfilenameonly”的内容。
在这种情况下,File file = new File(".", args[0])
是必要的
找到文件(注意传递的第一个参数)。
所有平台:File.getParent()
不返回父目录,
它应该返回“..”或文件系统中父目录的名称
具体方式。
如果您创建文件“myfilenameonly”而未指定完整路径
例如,File.getParent()
到它所在的目录,
将返回null。
进一步了解:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=1228537