运行jar时的当前目录路径

时间:2019-05-01 14:21:35

标签: java netbeans

我的程序通过从当前目录读取xml文件来读取配置数据:

File fXmlFile = new File("configFile.xml");

它在NetBeans IDE中正常工作。我已经建立了项目并得到了jar文件。如果我在Windows 10中双击它,它将运行良好。如果我通过右键单击jar打开文件,而Open with -> Java程序找不到配置文件。在这种情况下,我出现了异常:

java.io.FileNotFoundException: C:\Windows\System32\configFile.xml (The system cannot find the file specified)

为什么它看起来只是系统路径而不是当前目录?在Open with -> Java情况下运行时,如何要求程序将文件加载到当前目录中?

Jar的清单文件:

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.10.4
Created-By: 12.0.1+12 (Oracle Corporation)
Class-Path: lib/log4j-api-2.11.2.jar lib/log4j-core-2.11.2.jar lib/met
 ouia.jar lib/swt.jar
X-COMMENT: Main-Class will be added automatically by build
Main-Class: com.aaa.myprog.runMe 

3 个答案:

答案 0 :(得分:1)

正如Victor已经指出的那样,当前目录取决于用于启动JVM的命令,因此在运行时是动态的。相反,您需要一个依赖于jar文件本身位置的定位器,这意味着它在编译时是动态的,而在运行时是静态的。

这里有不同的方法,所以让我简短介绍两种:

使用启动脚本
这样,您只需要自己控制命令行即可,但是您必须在计划使用程序的每个操作系统上进行控制。在Windows上看起来可能像这样:

app.bat:

cd %~dp0
java -jar app.jar

第一行here上的更多信息。

使用系统ClassLoader
之所以可行,是因为System ClassLoader的源在编译时是动态的,而在运行时是静态的,因此正是您所需要的。但是,这样做的缺点是,您只能写入InputStream,因此无法写入配置文件。

app.jar

try (InputStream fXml = ClassLoader.getSystemClassLoader().getResourceAsStream("configFile.xml")) {
    ...
}

还有完整的MCVE。

ConfigFile.java:

public class ConfigFile {
    public static void main(String[] args) {
        try (final BufferedReader configFile = new BufferedReader(
            new InputStreamReader(ClassLoader.getSystemClassLoader()
                .getResourceAsStream("configFile.txt")))) {
            System.out.println(configFile.readLine());
        } catch (final IOException exc) {
            exc.printStackTrace();
        }
    }
}

ConfigFile.txt

Hello World

MANIFEST.MF

Manifest-Version: 1.0
Class-Path: .
Main-Class: prv.izruo.test.ConfigFile

命令行

P:\workspace\ConfigFile>dir deploy
...
02.05.2019  20:43             1.434 configFile.jar
02.05.2019  20:43                11 configFile.txt

P:\workspace\ConfigFile>java -jar deploy\configFile.jar
Hello World

答案 1 :(得分:1)

阅读for (int i = 0; i < 100000; i ++) { // Set the cursor to the beginning (0) of the current line (Console.CursorTop) Console.SetCursorPosition(0, Console.CursorTop); Console.Write("count: " + i); } 和应用程序可能需要的其他资产的最佳方法是将它们放在config.xml中,然后将它们作为类路径中的文件引用,如下所示:

Shell

src/main/resources

Java代码

mv configFile.xml /users/vico/my_program/src/main/resources

(此代码是从volumes借来的)

然后,您可以将jar移到任意位置,甚至将其运送给用户,而不必担心配置文件的位置。

答案 2 :(得分:-1)

我看到问题的出现是因为您需要了解在执行时如何解析相对路径,并且在此引用中会出现“当前目录”,所以请允许我解释一下

据我所知,“当前目录”也称为工作目录,它是在启动Java应用程序时设置的,它假定执行目录的值Java命令启动应用程序

例如:

如果打开命令终端,然后将自己置于目录"C:\pepe"中,然后从该目录中执行命令以启动jar,例如:java -jar "c:\path\to\my\app.jar",则工作目录为{ {1}},并且在您的程序中,所有对相对路径的引用都将使用"c:\pepe\"前缀来完成。

然后,它们的行"c:\pepe\"将指示jvm在File fXmlFile = new File("configFile.xml");处查找文件,因为相对路径"c:\pepe\configFile.xml"将使用工作目录来解析(先前在启动时设置) ),如上所述。

请记住java如何使用工作目录作为前缀来设置工作目录以及如何解析相对路径,从现在开始帮助您解决任何引用问题!

您可能会发现此链接有用Getting the Current Working Directory in Java用于调查netbeans在为我们启动Java应用程序时设置的工作目录是什么。

TD; DR:

“ pepe”是西班牙语,等于英语中的“ foo”:D,希望学点新知识! :D