Текущий путь к каталогу при запуске jar - PullRequest
1 голос
/ 01 мая 2019

Моя программа считывает данные конфигурации, читая xml-файл из текущего каталога:

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

Отлично работает в IDE NetBeans. У меня есть проект сборки и получил файл 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 случае?

Файл манифеста Джара:

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 ]

1 голос
/ 01 мая 2019

Текущий каталог, как уже отмечал Виктор, зависит от команды, используемой для запуска JVM, и поэтому является динамическим во время выполнения.Вместо этого вам нужен локатор, который зависит от расположения самого файла JAR, то есть он динамический во время компиляции, но статический во время выполнения.

Здесь есть разные подходы, поэтому позвольте мне кратко представить два:

Использование сценария запуска
Таким образом, вы просто управляете командной строкой самостоятельно, но вы должны делать это для каждой операционной системы, в которой вы планируете использовать вашу программу.В Windows это может выглядеть так:

app.bat:

cd %~dp0
java -jar app.jar

Дополнительная информация о первой строке здесь .

Использовать System 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 голос
/ 01 мая 2019

Лучший способ прочитать config.xml и другие ресурсы, которые могут понадобиться вашему приложению, это поместить их в src/main/resources и затем сослаться на них как файлы в вашем classpath, например:

Shell

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

Java-код

// ...

public static File getResourceAsFile(String resourcePath) {
    try {
        InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(resourcePath);
        if (in == null) {
            return null;
        }

        File tempFile = File.createTempFile(String.valueOf(in.hashCode()), ".tmp");
        tempFile.deleteOnExit();

        try (FileOutputStream out = new FileOutputStream(tempFile)) {
            //copy stream
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = in.read(buffer)) != -1) {
                out.write(buffer, 0, bytesRead);
            }
        }
        return tempFile;
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
}

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

// ...

(этот код был заимствован у ответа на этот стекопоток )

Затем вы можете переместить банку куда угодно, даже отправить ее своим пользователям и перестать беспокоиться о том, где находятся файлы конфигурации.

0 голосов
/ 01 мая 2019

Как я вижу, проблема возникает из-за того, что вам нужно знать , как относительные пути разрешаются во время выполнения , и "текущая директория" происходит на этом этапе, поэтому позвольте мне объяснить немного.

Насколько я знаю, «текущий каталог» также известен как рабочий каталог , и он устанавливается при запуске приложения Java, и он принимает значение каталога, из которого вы выполняете Java-команда для запуска приложения .

Так, например:

Если вы откроете командный терминал и поместите себя в каталог "C:\pepe", и из этого каталога вы выполните команду для запуска вашего jar, например: java -jar "c:\path\to\my\app.jar", тогда рабочий каталог будет "c:\pepe\" и внутри В вашей программе любая ссылка на относительный путь будет завершена с использованием префикса "c:\pepe\".

И эта строка File fXmlFile = new File("configFile.xml"); будет указывать jvm посмотреть файл на "c:\pepe\configFile.xml", так как относительный путь configFile.xml будет разрешен с использованием рабочего каталога (установленного ранее во время запуска), как я объяснил выше.

Имея в виду, как java устанавливает рабочий каталог, и , как относительные пути разрешаются , используя рабочий каталог в качестве префикса, теперь вы можете решить любую справочную проблему!

Вы можете найти эту ссылку полезной : Получение текущего рабочего каталога в Java для исследования того, какова рабочая директория, установленная netbeans при запуске (для нас) приложения java.

TD; DR:

«pepe» - испанский термин, равный «foo» в английском термине: D, надеюсь узнать что-то новое !! : D

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...