【问题标题】:Read properties file outside JAR file读取 JAR 文件外的属性文件
【发布时间】:2012-02-05 05:07:33
【问题描述】:

我有一个 JAR 文件,我的所有代码都在其中存档以供运行。我必须访问一个需要在每次运行之前更改/编辑的属性文件。我想将属性文件保存在 JAR 文件所在的同一目录中。有没有办法告诉 Java 从该目录中获取属性文件?

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

【问题讨论】:

  • 参见this answer - “而是将'default'文件存储在Jar中。如果更改了,请将更改后的文件存储在另一个位置。一个常见的位置是user.home。检查文件时,首先检查文件系统上是否存在修改过的文件,如果不存在则加载默认文件。" BTW “我不想要..” 你想要的不如有效的和实用的重要。存储应用程序。 Oracle 和 MS(可能还有其他人)都强烈反对应用程序目录中的设置。
  • 我之所以需要将properties文件保留在jar目录中,是因为在将整个目录(包括jar和property)复制到另一台机器运行时,最好将它们保留在一起。
  • 如果我强制用户传递属性文件路径,那么他每次从不同的机器运行批处理文件时都需要更改它。

标签: java properties


【解决方案1】:

因此,您希望将与 main/runnable jar 位于同一文件夹中的 .properties 文件视为文件而不是 main/runnable 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();
}

【讨论】:

  • 此解决方案有效。感谢您了解确切的要求和详细的代码。我验证了属性文件不在 jar 文件中,但它仍然可以从 jar 文件所在的同一目录访问该文件。这样就不需要绝对路径硬代码。 jar 和属性文件现在都可以复制到任何目录并独立运行。
  • 如果从外部执行命令将找不到该文件,例如:{{java -jar build/main.jar}}。你有什么解决办法吗,@eee?
  • @Darian 这里没有什么可修复的;它仅在 jar 和属性文件必须与我在文件组织架构中描述的相同的 ./ 根文件夹(相同的目录级别)上的情况下按设计工作。 (按原发帖人要求)
  • @Darian,所以如果你想执行java -jar build/main.jar,你需要把属性文件放在build文件夹中,这样它就和jar在同一目录级别。跨度>
  • 感谢您的回复@eee,问题是我不知道用户将在哪里执行java -jar path/to/jar/file。但我在另一个问题中找到了解决方案:String path = ClassLoader.getSystemClassLoader().getResource(".").getPath() + "/main.properties";
【解决方案2】:

我是通过其他方式做到的。

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();但这一切都取决于文件所在的位置
  • 只需替换“jarPath.getParentFile().getAbsolutePath();”到“jarPath.getParent()”。然后像魅力一样工作。
  • 同样是我的问题,但我有弹簧基础项目。如何告诉spring该文件在jar文件旁边?任何想法
【解决方案3】:

从 jar 文件访问文件目录中的文件总是有问题。在 jar 文件中提供类路径非常有限。而是尝试使用 bat 文件或 sh 文件来启动您的程序。通过这种方式,您可以随意指定类路径,引用系统上任何位置的任何文件夹。

同时查看我对这个问题的回答:

making .exe file for java project containing sqlite

【讨论】:

    【解决方案4】:

    我有一个类似的情况:希望我的*.jar 文件访问所述*.jar 文件旁边的目录中的文件。也请参考THIS ANSWER

    我的文件结构是:

    ./ - 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做任何你想做的事情

    【讨论】:

      【解决方案5】:

      我有一个通过类路径或使用 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
      

      【讨论】:

        【解决方案6】:

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

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

        【讨论】:

          【解决方案7】:

          这对我有用。从current directory 加载您的属性文件。

          注意:方法Properties#loaduses ISO-8859-1 encoding

          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 中运行。

          【讨论】:

            【解决方案8】:
            File parentFile = new File(".");
            String parentPath = file.getCanonicalPath();
            File resourceFile = new File(parentPath+File.seperator+"<your config file>");
            

            【讨论】:

            • 请在您的回答中添加一些解释。
            猜你喜欢
            • 1970-01-01
            • 2019-04-23
            • 2016-11-29
            • 1970-01-01
            • 2017-11-14
            • 2017-06-04
            • 1970-01-01
            • 2016-08-04
            • 1970-01-01
            相关资源
            最近更新 更多