JAR 파일 외부의 특성 파일 읽기


131

모든 코드가 실행되도록 보관되는 JAR 파일이 있습니다. 각 실행 전에 변경 / 편집 해야하는 속성 파일에 액세스해야합니다. JAR 파일이있는 동일한 디렉토리에 특성 파일을 유지하고 싶습니다. 어쨌든 Java에게 해당 디렉토리에서 특성 파일을 선택하도록 지시합니까?

참고 : 속성 파일을 홈 디렉토리에 유지하거나 명령 줄 인수에서 속성 파일의 경로를 전달하고 싶지 않습니다.


2
이 답변을 참조하십시오 - " '기본'파일을 Jar 안에 저장하십시오. 파일이 변경되면 변경된 파일을 다른 곳에 저장하십시오. 하나의 공통 위치는의 하위 디렉토리입니다 user.home. 파일을 확인할 때 먼저 파일의 존재 여부를 확인하십시오 파일 시스템에 변경된 파일이 존재하지 않는 경우 기본 파일을로드하십시오. " BTW "나는 원하지 않는다." 당신이 원하는 것은 효과적이고 실용적인 것보다 덜 중요하다. 앱 저장 애플리케이션 디렉토리의 설정은 Oracle & MS (및 기타)에 의해 권장되지 않습니다.
Andrew Thompson

3
jar 디렉토리에 특성 파일을 유지해야하는 이유는 전체 디렉토리 (jar 및 property 포함)가 다른 시스템에 복사되어 실행될 때 이들을 함께 유지하는 것이 좋습니다.
Neil

그리고 사용자가 속성 파일 경로를 강제로 전달하면 다른 시스템에서 배치 파일을 실행할 때마다 경로를 변경해야합니다.
Neil

답변:


144

따라서 .properties파일을 기본 / 실행 가능 jar와 동일한 폴더에있는 기본 / 실행 가능 jar의 자원이 아닌 파일로 취급하려고합니다. 이 경우 내 솔루션은 다음과 같습니다.

우선 : 프로그램 파일 아키텍처는 다음과 같아야합니다 (주 프로그램이 main.jar이고 주 속성 파일이 main.properties라고 가정).

./ - the root of your program
 |__ main.jar
 |__ main.properties

이 아키텍처를 사용하면 main.jar이 실행되기 전이나 실행중인 동안 (프로그램의 현재 상태에 따라) 텍스트 기반 파일이므로 main.properties 파일의 모든 속성을 수정할 수 있습니다. 예를 들어 main.properties 파일에는 다음이 포함될 수 있습니다.

app.version=1.0.0.0
app.name=Hello

따라서 루트 /베이스 폴더에서 기본 프로그램을 실행하면 일반적으로 다음과 같이 실행됩니다.

java -jar ./main.jar

또는 바로 :

java -jar main.jar

main.jar에서 main.properties 파일에있는 모든 특성에 대해 몇 가지 유틸리티 메소드를 작성해야합니다. app.version속성에 getAppVersion()다음과 같은 방법 이 있다고 가정 해 봅시다 .

/**
 * Gets the app.version property value from
 * the ./main.properties file of the base folder
 *
 * @return app.version string
 * @throws IOException
 */

import java.util.Properties;

public static String getAppVersion() throws IOException{

    String versionString = null;

    //to load application's properties, we use this class
    Properties mainProperties = new Properties();

    FileInputStream file;

    //the base folder is ./, the root of the main.properties file  
    String path = "./main.properties";

    //load the file handle for main.properties
    file = new FileInputStream(path);

    //load all the properties from this file
    mainProperties.load(file);

    //we have loaded the properties, so close the file handle
    file.close();

    //retrieve the property we are intrested, the app.version
    versionString = mainProperties.getProperty("app.version");

    return versionString;
}

app.version값 을 필요로하는 메인 프로그램의 어느 부분에서나 다음과 같이 메소드를 호출합니다.

String version = null;
try{
     version = getAppVersion();
}
catch (IOException ioe){
    ioe.printStackTrace();
}

7
이 솔루션이 작동합니다. 정확한 요구 사항과 자세한 코드를 이해해 주셔서 감사합니다. 속성 파일이 jar 파일 안에 없지만 jar 파일이있는 동일한 디렉토리에서 파일에 액세스 할 수 있음을 확인했습니다. 이런 식으로 절대 경로 하드 코드가 필요하지 않습니다. jar 및 특성 파일을 이제 임의의 디렉토리로 복사하고 독립적으로 실행할 수 있습니다.
Neil

3
예를 들어 {{java -jar build / main.jar}}에 대해 외부에서 명령을 실행하면 파일을 찾을 수 없습니다. @eee에 대한 해결책이 있습니까?
Darian

@Darian 여기서 고칠 것이 없다. jar 및 속성 파일 ./이 파일 구성 아키텍처에서 설명한 것과 동일한 루트 폴더 (동일한 디렉토리 수준) 에 있어야하는 곳에서 설계된대로 작동합니다 . (원래 포스터에 의해 설정된 요구 사항에 따라)
ecle

@Darian이므로 실행 java -jar build/main.jar하려면 속성 파일을 buildjar와 동일한 디렉토리 수준에 있도록 폴더에 속성 파일을 넣어야합니다 .
ecle

7
귀하의 답변 @eee에 감사드립니다. 문제는 사용자가 어디를 실행할지 모르겠습니다 java -jar path/to/jar/file. 그러나 다른 질문에서 해결책을 찾았습니다.String path = ClassLoader.getSystemClassLoader().getResource(".").getPath() + "/main.properties";
Darian

42

나는 다른 방법으로 해냈습니다.

Properties prop = new Properties();
    try {

        File jarPath=new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().getPath());
        String propertiesPath=jarPath.getParentFile().getAbsolutePath();
        System.out.println(" propertiesPath-"+propertiesPath);
        prop.load(new FileInputStream(propertiesPath+"/importer.properties"));
    } catch (IOException e1) {
        e1.printStackTrace();
    }
  1. Jar 파일 경로를 가져옵니다.
  2. 해당 파일의 부모 폴더를 가져옵니다.
  3. 속성 파일 이름과 함께 InputStreamPath에서 해당 경로를 사용하십시오.

getParentFile () 부분을 삭제해야하므로 대신 다음을 사용했습니다. String propertiesPath = jarPath.getAbsolutePath (); 파일의 위치에 따라 다릅니다.
MobileMon

4
"jarPath.getParentFile (). getAbsolutePath ();"를 바꾸십시오. "jarPath.getParent ()". 그때 매력처럼 작동합니다.
StackAddict

1
내 경우에도 같은 문제이지만 스프링베이스 프로젝트가 있습니다. 그 파일이 jar 파일 옆에 있음을 봄에 알리는 방법은 무엇입니까? 어떤 아이디어
Mubasher

3

jar 파일에서 파일 디렉토리의 파일에 액세스하는 데 항상 문제가 있습니다. jar 파일에 클래스 경로를 제공하는 것은 매우 제한적입니다. 대신 bat 파일이나 sh 파일을 사용하여 프로그램을 시작하십시오. 이런 식으로 시스템의 어느 곳에서나 폴더를 참조하여 원하는대로 클래스 경로를 지정할 수 있습니다.

또한이 질문에 대한 대답을 확인하십시오.

sqlite를 포함하는 Java 프로젝트의 .exe 파일 만들기


1

비슷한 경우 *.jar가 있습니다. 파일이 해당 파일 옆의 디렉토리에있는 파일에 액세스하기를 원합니다 *.jar. 이 답변 도 참조하십시오 .

내 파일 구조는 다음과 같습니다

./ - the root of your program
|__ *.jar
|__ dir-next-to-jar/some.txt

다음과 같이 파일 (예 some.txt:)을 *.jar파일 내부의 InputStream 에로드 할 수 있습니다 .

InputStream stream = null;
    try{
        stream = ThisClassName.class.getClass().getResourceAsStream("/dir-next-to-jar/some.txt");
    }
    catch(Exception e) {
        System.out.print("error file to stream: ");
        System.out.println(e.getMessage());
    }

그런 다음 원하는대로 stream


0

log4j2.properties를 사용하여 클래스 경로 또는 외부 구성에서 모두 수행하는 예가 있습니다.

package org.mmartin.app1;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.LogManager;


public class App1 {
    private static Logger logger=null; 
    private static final String LOG_PROPERTIES_FILE = "config/log4j2.properties";
    private static final String  CONFIG_PROPERTIES_FILE = "config/config.properties";

    private Properties properties= new Properties();

    public App1() {
        System.out.println("--Logger intialized with classpath properties file--");
        intializeLogger1();
        testLogging();
        System.out.println("--Logger intialized with external file--");
        intializeLogger2();
        testLogging();
    }




    public void readProperties()  {
        InputStream input = null;
        try {
            input = new FileInputStream(CONFIG_PROPERTIES_FILE);
            this.properties.load(input);
        } catch (IOException e) {
            logger.error("Unable to read the config.properties file.",e);
            System.exit(1);
        }
    }

    public void printProperties() {
        this.properties.list(System.out);
    }

    public void testLogging() {
        logger.debug("This is a debug message");
        logger.info("This is an info message");
        logger.warn("This is a warn message");
        logger.error("This is an error message");
        logger.fatal("This is a fatal message");
        logger.info("Logger's name: "+logger.getName());
    }


    private void intializeLogger1() {
        logger = LogManager.getLogger(App1.class);
    }
    private void intializeLogger2() {
        LoggerContext context = (org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false);
        File file = new File(LOG_PROPERTIES_FILE);
        // this will force a reconfiguration
        context.setConfigLocation(file.toURI());
        logger = context.getLogger(App1.class.getName());
    }

    public static void main(String[] args) {
        App1 app1 = new App1();
        app1.readProperties();
        app1.printProperties();
    }
}


--Logger intialized with classpath properties file--
[DEBUG] 2018-08-27 10:35:14.510 [main] App1 - This is a debug message
[INFO ] 2018-08-27 10:35:14.513 [main] App1 - This is an info message
[WARN ] 2018-08-27 10:35:14.513 [main] App1 - This is a warn message
[ERROR] 2018-08-27 10:35:14.513 [main] App1 - This is an error message
[FATAL] 2018-08-27 10:35:14.513 [main] App1 - This is a fatal message
[INFO ] 2018-08-27 10:35:14.514 [main] App1 - Logger's name: org.mmartin.app1.App1
--Logger intialized with external file--
[DEBUG] 2018-08-27 10:35:14.524 [main] App1 - This is a debug message
[INFO ] 2018-08-27 10:35:14.525 [main] App1 - This is an info message
[WARN ] 2018-08-27 10:35:14.525 [main] App1 - This is a warn message
[ERROR] 2018-08-27 10:35:14.525 [main] App1 - This is an error message
[FATAL] 2018-08-27 10:35:14.525 [main] App1 - This is a fatal message
[INFO ] 2018-08-27 10:35:14.525 [main] App1 - Logger's name: org.mmartin.app1.App1
-- listing properties --
dbpassword=password
database=localhost
dbuser=user

0

이것은 나를 위해 작동합니다. 에서 특성 파일을로드하십시오.current directory

Properties properties = new Properties();
properties.load(new FileReader(new File(".").getCanonicalPath() + File.separator + "java.properties"));
properties.forEach((k, v) -> {
            System.out.println(k + " : " + v);
        });

즉, 확인 java.properties상기입니다 current directory. 이전과 같이 올바른 디렉토리로 전환하는 작은 시작 스크립트를 작성할 수 있습니다.

#! /bin/bash
scriptdir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 
cd $scriptdir
java -jar MyExecutable.jar
cd -

java.propertiesIDE 에서이 코드를 작동시키기 위해 프로젝트 에서 파일을 프로젝트 루트에 넣으십시오 .


0

여기서 언급 .getPath()한 경우 Jar의 경로를 반환하고 jar과 함께 배치 된 다른 모든 구성 파일을 참조하려면 부모가 필요하다고 생각합니다. 이 코드는 Windows에서 작동합니다. 메인 클래스 내에 코드를 추가하십시오.

File jarDir = new File(MyAppName.class.getProtectionDomain().getCodeSource().getLocation().getPath());
String jarDirpath = jarDir.getParent();

System.out.println(jarDirpath);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.