简体   繁体   English

通过Eclipse运行时,Java无法找到文件

[英]Java can't find file when running through Eclipse

When I run a Java application that should be reading from a file in Eclipse, I get a java.io.FileNotFoundException , even though the file is in the correct directory. 当我运行应该从Eclipse中的文件读取的Java应用程序时,我得到一个java.io.FileNotFoundException ,即使该文件位于正确的目录中。 I can compile and run the application from the command line just fine; 我可以从命令行编译并运行应用程序就好了; the problem only occurs in Eclipse, with more than one project and application. 该问题仅发生在Eclipse中,具有多个项目和应用程序。 Is there a setting I need to change in the run configurations or build paths to get it to find the file correctly? 是否需要在运行配置或构建路径中更改设置以使其正确查找文件?

The problem is most likely that your application is using a relative pathname. 问题很可能是您的应用程序使用的是相对路径名。 As @BalusC says, relative pathnames can be problematic. 正如@BalusC所说,相对路径名可能会有问题。 But IMO, he goes way too far when he says "[y]ou should never use relative paths in java.io stuff" . 但IMO,当他说“你永远不应该在java.io的东西中使用相对路径”时,他走得太远了。

When an application opens a file using (for example) the FileInputStream(File) constructor, relative pathnames are resolved relative to the "current directory" in a process described as follows in the javadoc for File.getAbsolutePath() . 当应用程序使用(例如) FileInputStream(File)构造函数打开文件时,相对于“当前目录”,相对于“当前目录”,在File.getAbsolutePath()的javadoc中描述的过程中解析相对路径名。

[...] Otherwise this pathname is resolved in a system-dependent way. [...]否则,此路径名将以系统相关的方式解析。 On UNIX systems, a relative pathname is made absolute by resolving it against the current user directory. 在UNIX系统上,通过将相对路径名解析为当前用户目录,使其成为绝对路径名。 On Microsoft Windows systems, a relative pathname is made absolute by resolving it against the current directory of the drive named by the pathname, if any; 在Microsoft Windows系统上,通过将路径名解析为路径名所指定的驱动器的当前目录(如果有),使相对路径名成为绝对路径名; if not, it is resolved against the current user directory. 如果没有,则针对当前用户目录解析。

So immediately, we see that the notion of "current directory" has different nuances on Windows and UNIX platforms. 所以我们立即看到“当前目录”的概念在Windows和UNIX平台上有不同的细微差别。 The second issue is that in pure Java you cannot definitively find out what the current directory is, and you certainly cannot change it for the current JVM using pure Java. 第二个问题是,在纯Java中,您无法明确地找出当前目录是什么,并且您当然无法使用纯Java为当前JVM更改它。 (When the JVM starts, the "user.dir" system property is set to the current directory, but there is nothing stopping an application from changing the property so you cannot entirely rely on it. Furthermore, changing "user.dir" only changes the way that the empty path is resolved, not relative paths in general.) (当JVM启动时,“user.dir”系统属性被设置为当前目录,但没有什么能阻止应用程序更改属性,因此您无法完全依赖它。此外,更改“user.dir”只会更改解决空路径的方式,而不是一般的相对路径。)

So what should you do about this? 那么你应该怎么做呢?

  • One option is to use absolute pathnames to refer to files. 一种选择是使用绝对路径名来引用文件。 This is reliable in (almost) all cases, but using absolute pathnames can be problematic if the user has to enter the pathname, or if you need to avoid hard-wired (or configured) absolute pathnames. 这在(几乎)所有情况下都是可靠的,但如果用户必须输入路径名,或者如果您需要避免硬连线(或配置)的绝对路径名,则使用绝对路径名可能会有问题。

  • A second option is to use classpath relative pathnames and locate files relative to the application's installation directory. 第二种选择是使用类路径相对路径名并找到相对于应用程序安装目录的文件。 This works if that is what you need to do, but presents a problem if you need to pass a File to some library method. 如果您需要这样做,这可以工作,但如果您需要将File传递给某个库方法,则会出现问题。 It also doesn't help if you are trying to find the user's application preferences. 如果您正在尝试查找用户的应用程序首选项,它也无济于事。 (In general, putting user preferences into the installation directory is a mistake ...) (通常,将用户首选项放入安装目录是错误的......)

  • A third option is to name a file relative to some absolute directory that you get from somewhere else; 第三个选项是相对于从其他地方获得的某个绝对目录命名文件; eg new File(System.getProperty("home.dir"), "foo/bar"); 例如new File(System.getProperty("home.dir"), "foo/bar"); .

  • The final option is to use relative pathnames, and assume that the user knowing what the current directory. 最后一个选项是使用相对路径名,并假设用户知道当前目录是什么。 For many applications that the user runs from the command line, this is the right solution. 对于用户从命令行运行的许多应用程序,这是正确的解决方案。

In the particular case of Eclipse, there is a simple solution. 在Eclipse的特定情况下,有一个简单的解决方案。 Go to the "run configuration" that you are using to launch your application, open the "Arguments" tab, and click the "Other" radio button. 转到用于启动应用程序的“运行配置”,打开“参数”选项卡,然后单击“其他”单选按钮。 Then enter an absolute pathname as the working directory for the launched application. 然后输入绝对路径名作为已启动应用程序的工作目录。 When the child JVM is launched, it will have the specified working directory as its current directory. 启动子JVM时,它将指定的工作目录作为其当前目录。

Another option is to simply figure out what directory the "current path" points to in your environment -- whatever that is. 另一种选择是简单地找出“当前路径”指向您环境中的目录 - 无论是什么。 Once you figure out, you can choose your solution from there. 一旦你弄清楚,你可以从那里选择你的解决方案。 Maybe that is to use an appropriate relative path to your file's location or relocating the file. 也许这是使用适当的相对路径到您的文件的位置或重新定位文件。

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

When you create a default Java application in Eclipse, you get this directory structure: 在Eclipse中创建默认Java应用程序时,您将获得以下目录结构:

./ProjectName/ - root directory ./ProjectName/ - 根目录
./ProjectName/bin/ - output directory, containing .class files ./ProjectName/bin/ - 输出目录,包含.class文件
./ProjectName/src/ - source directory, containing .java files ./ProjectName/src/ - 源目录,包含.java文件

If your application requests "./data.txt" it will search for it relative to the root directory. 如果您的应用程序请求“./data.txt”,它将相对于根目录搜索它。 This is the "working directory" and can be configured in the arguments tab as per Martin's reply above. 这是“工作目录”,可以根据Martin上面的回复在参数选项卡中进行配置。

You say it works from the command line? 你说它可以从命令行工作吗? This is likely because you're inside either the bin or src folders when you run the java binary. 这可能是因为您在运行java二进制文件时位于bin或src文件夹中。 The working directory in this case is whichever directory the command prompt is currently inside. 在这种情况下,工作目录是命令提示符当前所在的目录。 If, for example, you go into the /src/ directory, say javac *.java then run the files from there, it will search for "./data.txt" within the /src/ directory. 例如,如果你进入/ src /目录,说javac *.java然后从那里运行文件,它将在/ src /目录中搜索“./data.txt”。 If you go inside the /bin/ directory and run your application from there, it will look for the file relative to the /bin/ directory. 如果你进入/ bin /目录并从那里运行你的应用程序,它将查找相对于/ bin /目录的文件。

I was having a similar problem , I placed my files in a folder named cobolcopybooks inside the src folder and tried to access them inside my project using classloader.getResource("cobolcopybooks/demostud.cob") but i was getting null pointer exception,i tried it several times by cleaning and building the workspaces after several failed attempts i realised that i was not refreshing the project to allow the files to get built along with the project. 我遇到了类似的问题,我将文件放在src文件夹中名为cobolcopybooks的文件夹中,并尝试使用classloader.getResource(“cobolcopybooks / demostud.cob”)在我的项目中访问它们,但我得到空指针异常,我经过多次尝试失败后,通过清理和构建工作区几次尝试了几次,我意识到我没有刷新项目以允许文件与项目一起构建。 ie these files should be visible along with other class files as at runtime the root directory will be bin directory and it's searching for those files there. 即这些文件应该与其他类文件一起可见,因为在运行时根目录将是bin目录,并且它在那里搜索那些文件。

You should never use relative paths in java.io stuff. 永远不应该在java.io使用相对路径。 The path would become dependent on the current working directory, which depends on the way how you started the application and is thus not per se the same on all environments. 该路径将依赖于当前工作目录,这取决于您启动应用程序的方式,因此在所有环境中本身并不相同。 This is uncontrollable from inside the Java application. 这在Java应用程序内部是无法控制的。 Portability trouble! 便携性问题! Always use absolute paths. 始终使用绝对路径。 Thus eg c:/path/to/file.ext or /path/to/file.ext (with the leading slash) for UNIX and consorts (or even Windows when the disk letter is irrelevant). 例如c:/path/to/file.ext/path/to/file.ext (带有前导斜杠)用于UNIX和consorts(当磁盘字母不相关时甚至是Windows)。

Whenever you'd like to ship some files along with your application, a common practice is to place them in the classpath as well. 每当您想要将一些文件与应用程序一起发送时,通常的做法是将它们放在类路径中。 This way you can just use ClassLoader#getResource() to get its location. 这样您就可以使用ClassLoader#getResource()来获取其位置。 It returns an URL . 它返回一个URL You can use URL#toURI() or URL#getPath() and pass it to constructor of java.io.File and then use it further the usual way. 您可以使用URL#toURI()URL#getPath()并将其传递给java.io.File构造函数,然后以通常的方式进一步使用它。

In your Eclipse project, the src folder (where your Java source goes) is basically the root of the classpath. 在Eclipse项目中, src文件夹(Java源代码所在的位置)基本上是类路径的根。 Further it of course also covers all other projects and (external) folders which are taken in the project's Build Path . 此外,它当然还涵盖了项目的构建路径中的所有其他项目和(外部)文件夹。

Assuming that you've placed the particular file in the root of the classpath: 假设您已将特定文件放在类路径的根目录中:

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

You can even use ClassLoader#getResourceAsStream() to directly get an InputStream : 您甚至可以使用ClassLoader#getResourceAsStream()直接获取InputStream

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

If it's placed inside a package, then you can just use the usual pathnames: 如果它放在包中,那么你可以使用通常的路径名:

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

or 要么

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

Assuming the user does not enter the full file path to the file and enter something like "myfilenameonly". 假设用户没有输入文件的完整文件路径并输入类似“myfilenameonly”的内容。 File file = new File(".", args[0]) is necessary in this case to locate the file (paying attention to the first argument passed). File file = new File(".", args[0])在这种情况下是必要的,以找到文件(注意传递的第一个参数)。

All platforms: File.getParent() does not return the parent directory, it should return ".." or the name of the parent directory in a file-system specific way. 所有平台: File.getParent()不返回父目录,它应以文件系统特定的方式返回“..”或父目录的名称。

If you create the File "myfilenameonly" without specifying the full path to the directory where it is located, the File.getParent() , for example, will return null. 如果创建文件“myfilenameonly”而未指定其所在目录的完整路径,则File.getParent()将返回null。

See further: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=1228537 进一步了解: http//bugs.sun.com/bugdatabase/view_bug.do?video_id = 1228537

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM