java - 如何安全地读取Java中的属性文件?

标签 java file properties-file

我有一个像这样的属性文件 -

emailFrom=hello@abc.com
emailTo=world@abc.com

# can be separated by comma
whichServer=UserServer,GuestServer

maxTestInSec=120
numberOfUsers=1000

现在我正在 Java 中读取这个属性文件,如果一切设置正确,它就可以工作 -

private static final Properties prop = new Properties();

private static String emailFrom;
private static String emailTo;
private static List<String> whichServer;
private static String maxTestInSec;
private static String numberOfUsers;

public static void main(String[] args) {
    readConfig(args);
}   

private void readConfig(String[] args) throws FileNotFoundException, IOException {
    if (!TestUtils.isEmpty(args) && args.length != 0) {
        prop.load(new FileInputStream(args[0]));
    } else {
        prop.load(TestTask.class.getClassLoader().getResourceAsStream("config.properties"));
    }

    emailFrom = prop.getProperty("emailFrom").trim();
    emailTo = prop.getProperty("emailTo").trim();
    whichServer = Arrays.asList(prop.getProperty("whichServer").trim().split(","));
    maxTestInSec = prop.getProperty("maxTestInSec").trim();
    numberOfUsers = prop.getProperty("numberOfUsers").trim();
}

问题陈述:-

我需要确保如果缺少任何属性值,那么我想使用默认值,如果有任何机会该属性被注释掉,那么我也想使用默认值,但我会记录一个警告消息指出该属性丢失或为空,因此使用默认值。我试图涵盖读取文件的所有极端情况 -

  • 现在假设,如果我没有为上述文件中的任何属性指定值,那么我想使用我未提供的属性的默认值,并记录为警告,指出没有值已为此属性提供,因此使用默认值。例如:假设我没有为 emailFrom 字段提供任何值,那么我想使用默认值 hello@abc.com 来实现类似的功能为他人。所有属性的默认值为:

emailFrom=hello@abc.com

emailTo=world@abc.com

whichServer=UserServer

maxTestInSec=30

numberOfUsers=500

  • 此外,如果任何属性被注释掉,则上述代码将通过 NPE 异常。在这种情况下如何使用默认值?

我应该开始使用命令行解析器吗?处理这些东西的最佳且干净的方法是什么?

我不想有很多 if block 来添加检查,然后设置默认值。

最佳答案

从 Java 8 开始,最简单的事情就是使用 getOrDefault()它允许您在 get-site 指定默认值。例如:

String email = properties.getOrDefault("emailFrom", "hello@abc.com");

这简洁明了,但确实意味着您需要在访问该属性的任何地方指定默认值。

如果这对您不起作用(即您将多次从属性对象中读取值),您可以使用对默认值的内置支持 - 请注意 constructor它采用 default Properties 对象。这使您可以构造一个包含默认值的 Properties 对象,然后当您加载用户的属性文件时,如果用户未指定值,它将回退到默认值。

private static final Properties DEFAULTS = new Properties();
static {
  DEFAULTS.setProperty("emailFrom", "hello@abc.com");
}

public Properties getProperties() {
  Properties props = new Properties(DEFAULTS);
  props.load(...);
  return props;
}

请注意,这与 Map 的构造函数的工作方式不同 - 默认值保留为单独的映射,并且只有 .getProperty() 也会查询默认值; Map 中定义的方法(如 .get())则不然。 Properties 扩展 Hashtable 是一个糟糕的决定,这是众多原因之一,但这就是生活......

<小时/>

这些选项有效,但它们都容易出错,因为 a) Properties 是可变的,b) 只有它的一些公共(public)方法会回退到 default 实例。我宁愿永远不要直接公开 Properties 对象,而是使用类型安全的方法创建一个包装类,该方法公开我的应用程序将关心的值。这需要更多的打字,但使用起来更安全。它看起来像这样:

public class ApplicationSettings {
  private final Properties properties = new Properties();
  public ApplicationSettings() {
    properties.load(...);
  }

  public String emailFrom() {
    // simple methods are concise, and encode the default right inline
    return properties.getOrDefault("emailFrom", "hello@abc.com");
  }

  public int getMaxTestSeconds() {
    // You can do more complex validation if you want, too
    String value = properties.get("maxTestInSec");
    if (value == null) {
      return 30;
    }
    int maxTestSeconds = Integer.parseInt(value);
    if (maxTestSeconds <= 0) {
      // could instead log a warning and return the default if you want
      throw new IllegalStateException(
          "maxTestInSec must be positive - was " + maxTestSeconds);
    }
    return maxTestSeconds;
  }
}

如果需要,您还可以公开 setter ,在将值添加到 Properties 对象之前以类似方式验证值,不过默认情况下将所有内容设置为只读通常是一个很好的做法。

关于java - 如何安全地读取Java中的属性文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27812810/

相关文章:

c - 在C中实时读取文件行

java - 如何在 Maven 中读取外部属性文件

java - 在java中使用 ' '内的属性字段值?

java - 关闭 Saxon 输出到控制台

java - 访问其他 View 工作集

java - Spring + Hibernate 的 Multi-Tenancy : "SessionFactory configured for multi-tenancy, but no tenant identifier specified"

python - json.load() 或 json.dump() 应该与 open() 上下文管理器一起使用吗?

linux - 如何在 bash 中的文件夹中的每个文件的开头添加一个字符串?

spring - 库 jar 可以从 Spring Cloud Config Server 读取属性吗?

java - 在 OSX 上使用捆绑的 JRE