在JAR文件之外读取属性文件


131

我有一个JAR文件,我的所有代码都已存档运行。我必须访问一个属性文件,每次运行前都需要对其进行更改/编辑。我想将属性文件保留在JAR文件所在的目录中。无论如何,有没有告诉Java从该目录中提取属性文件?

注意:我不想将属性文件保留在主目录中,也不想在命令行参数中传递属性文件的路径。


2
参见此答案 - “而是将'default'文件存储在Jar中。如果已更改,则将更改后的文件存储在另一个位置。一个常见的位置是。的子目录user.home。检查文件时,请先检查是否存在文件系统上已更改的文件,如果该文件不存在,请加载默认文件。” 顺便说一句 “我不想要..”您想要的东西比有效和实用的东西重要。正在储存应用程式。Oracle和MS(可能还有其他)都强烈建议不要在应用程序目录中进行设置。
安德鲁·汤普森

3
我需要将属性文件保留在jar目录中的原因是,当将整个目录(包括jar和property)复制到另一台机器并运行时,最好将它们保持在一起。
尼尔

而且,如果我强迫用户传递属性文件路径,那么他每次在不同计算机上运行批处理文件时都需要对其进行更改。
尼尔

Answers:


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和属性文件都可以复制到任何目录并独立运行。
2012年

3
如果从外部执行命令,例如{{java -jar build / main.jar}},将找不到该文件。您对此有任何解决办法吗,@ eee?
达里安

@Darian这里没有要修复的东西;它仅按设计工作,即jar和属性文件必须./与文件组织体系结构中所述的文件夹位于同一根文件夹(相同的目录级别)上。(按照原始海报设置的要求)
ecle

@Darian,因此,如果要执行java -jar build/main.jar,则还需要将属性文件放在build文件夹中,以便它与jar处于同一目录级别。
ecle

7
感谢您@eee的回复,问题是我不知道用户将在哪里执行java -jar path/to/jar/file。但我在另一个问题中找到了解决方案:String path = ClassLoader.getSystemClassLoader().getResource(".").getPath() + "/main.properties";
达里安(Darian)2015年

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()部分,所以我改用:字符串propertiesPath = jarPath.getAbsolutePath(); 但是这完全取决于文件所在的位置
MobileMon 2014年

4
只需替换“ jarPath.getParentFile()。getAbsolutePath();” 到“ jarPath.getParent()”。然后像魅力一样工作。
StackAddict 2015年

1
就我而言,问题也是一样,但我有spring base项目。如何判断Spring文件在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)加载到内部的InputStream中*.jar

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.properties文件放在项目根目录中,以使此代码也可以在您的IDE中工作。


0

在这里,如果您提到.getPath()那那将返回Jar的路径,我想您需要它的父级来引用与jar一起放置的所有其他配置文件。此代码在Windows上有效。在主类中添加代码。

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

System.out.println(jarDirpath);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.