通过 Eclipse 运行 Java 时找不到文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2792870/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 12:53:06  来源:igfitidea点击:

Java can't find file when running through Eclipse

javaeclipsefileexceptionfilereader

提问by derekerdmann

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. 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. Is there a setting I need to change in the run configurations or build paths to get it to find the file correctly?

当我运行一个应该从 Eclipse 中读取文件的 Java 应用程序时,我得到一个java.io.FileNotFoundException,即使该文件位于正确的目录中。我可以从命令行编译和运行应用程序就好了;问题只出现在Eclipse中,项目和应用程序不止一个。是否需要在运行配置或构建路径中更改设置才能正确查找文件?

采纳答案by Stephen C

The problem is most likely that your application is using a relative pathname. As @BalusC says, relative pathnames can be problematic. But IMO, he goes way too far when he says "[y]ou should neveruse relative paths in java.io stuff".

问题很可能是您的应用程序使用了相对路径名。正如@BalusC 所说,相对路径名可能有问题。但是 IMO,当他说“[y]ou永远不应该在 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)构造函数打开文件时,相对路径名在 javadoc for File.getAbsolutePath().

[...] 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. 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; if not, it is resolved against the current user directory.

[...] 否则,此路径名将以依赖于系统的方式解析。在 UNIX 系统上,相对路径名通过针对当前用户目录进行解析而成为绝对路径名。在 Microsoft Windows 系统上,相对路径名通过针对由路径名命名的驱动器的当前目录(如果有)进行解析而成为绝对路径名;如果不是,则针对当前用户目录进行解析。

So immediately, we see that the notion of "current directory" has different nuances on Windows and UNIX platforms. 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. (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 propertyso 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.)

因此,我们立即看到“当前目录”的概念在 Windows 和 UNIX 平台上有不同的细微差别。第二个问题是,在纯 Java 中,您无法确定当前目录是什么,并且您当然无法使用纯 Java 为当前 JVM 更改它。(当 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 Fileto some library method. 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; e.g. 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.

  • 一种选择是使用绝对路径名来引用文件。这在(几乎)所有情况下都是可靠的,但如果用户必须输入路径名,或者如果您需要避免硬连线(或配置)绝对路径名,则使用绝对路径名可能会出现问题。

  • 第二个选项是使用类路径相对路径名并定位相对于应用程序安装目录的文件。如果这是您需要做的,这会起作用,但如果您需要将 a 传递File给某个库方法,则会出现问题。如果您试图查找用户的应用程序首选项,它也无济于事。(一般情况下,把用户首选项放到安装目录是错误的...)

  • 第三种选择是相对于您从其他地方获得的某个绝对目录命名文件;例如new File(System.getProperty("home.dir"), "foo/bar");

  • 最后一个选项是使用相对路径名,并假设用户知道当前目录是什么。对于用户从命令行运行的许多应用程序,这是正确的解决方案。

In the particular case of Eclipse, there is a simple solution. 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.

在 Eclipse 的特殊情况下,有一个简单的解决方案。转到用于启动应用程序的“运行配置”,打开“参数”选项卡,然后单击“其他”单选按钮。然后输入一个绝对路径名作为启动应用程序的工作目录。当子 JVM 启动时,它会将指定的工作目录作为其当前目录。

回答by Gunslinger47

When you create a default Java application in Eclipse, you get this directory structure:

在 Eclipse 中创建默认 Java 应用程序时,您将获得以下目录结构:

./ProjectName/- root directory
./ProjectName/bin/- output directory, containing .class files
./ProjectName/src/- source directory, containing .java files

./ProjectName/- 根目录
./ProjectName/bin/- 输出目录,包含 .class 文件
./ProjectName/src/- 源目录,包含 .java 文件

If your application requests "./data.txt" it will search for it relative to the root directory. This is the "working directory" and can be configured in the arguments tab as per Martin's reply above.

如果您的应用程序请求“./data.txt”,它将相对于根目录搜索它。这是“工作目录”,可以根据上面 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. 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 *.javathen run the files from there, it will search for "./data.txt" within the /src/ directory. If you go inside the /bin/ directory and run your application from there, it will look for the file relative to the /bin/ directory.

你说它从命令行工作?这可能是因为您在运行 java 二进制文件时位于 bin 或 src 文件夹中。在这种情况下,工作目录是命令提示符当前所在的目录。例如,如果您进入 /src/ 目录,javac *.java然后从那里运行文件,它将在 /src/ 目录中搜索“./data.txt”。如果您进入 /bin/ 目录并从那里运行您的应用程序,它将查找与 /bin/ 目录相关的文件。

回答by BalusC

You should neveruse relative paths in java.iostuff. 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. Portability trouble! Always use absolute paths. Thus e.g. c:/path/to/file.extor /path/to/file.ext(with the leading slash) for UNIX and consorts (or even Windows when the disk letter is irrelevant).

永远不应该在java.io东西中使用相对路径。该路径将依赖于当前工作目录,这取决于您启动应用程序的方式,因此在所有环境中本身并不相同。这是从 Java 应用程序内部无法控制的。便携麻烦!始终使用绝对路径。因此,例如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 classpathas well. This way you can just use ClassLoader#getResource()to get its location. It returns an URL. You can use URL#toURI()or URL#getPath()and pass it to constructor of java.io.Fileand then use it further the usual way.

每当您想随应用程序一起发送一些文件时,通常的做法是将它们也放在类路径中。这样你就可以使用它ClassLoader#getResource()来获取它的位置。它返回一个URL. 您可以使用URL#toURI()orURL#getPath()并将其传递给 of 的构造函数,java.io.File然后以通常的方式进一步使用它。

In your Eclipse project, the srcfolder (where your Java source goes) is basically the root of the classpath. Further it of course also covers all other projects and (external) folders which are taken in the project's Build Path.

在您的 Eclipse 项目中,src文件夹(您的 Java 源代码所在的位置)基本上是类路径的根目录。此外,它当然还涵盖了在项目的Build Path中采用的所有其他项目和(外部)文件夹。

Assuming that you've placed the particular file in the rootof 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");
// ...

回答by Marcos Le?o

Assuming the user does not enter the full file path to the file and enter something like "myfilenameonly". File file = new File(".", args[0])is necessary in this case to locate the file (paying attention to the first argument passed).

假设用户没有输入文件的完整文件路径并输入类似“myfilenameonly”的内容。 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?bug_id=1228537

回答by Farheen Mohammad

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. i.e 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.

我遇到了类似的问题,我将我的文件放在 src 文件夹内名为 cobolcopybooks 的文件夹中,并尝试使用 classloader.getResource("cobolcopybooks/demostud.cob") 在我的项目中访问它们,但我得到了空指针异常,我在多次尝试失败后,通过清理和构建工作区尝试了几次,我意识到我没有刷新项目以允许文件与项目一起构建。即这些文件应该与其他类文件一起可见,因为在运行时根目录将是 bin 目录,它正在那里搜索这些文件。

回答by tgmoor

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);