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

时间:2015-01-07 05:14:08

标签: 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块来添加支票然后设置默认值。

3 个答案:

答案 0 :(得分:1)

从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扩展Properties是一个可怕的决定的原因之一,但是c&#39; est la vie ...

这些选项有效,但它们都容易出错,因为a)default是可变的,而b)只有一些公共方法可以回退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; } } 个对象,而是使用类型安全的方法创建一个包装类,公开我的应用程序将关注的值。这是一个更多的打字,但它更安全。它看起来像这样:

Properties

如果需要,还可以在将值添加到DocumentCollection collectionInfo = new DocumentCollection(); collectionInfo.Id = collectionName; // Configure collections for maximum query flexibility including string range queries. collectionInfo.IndexingPolicy = new IndexingPolicy(new RangeIndex(DataType.String) { Precision = -1 }); 对象之前公开类似验证值的setter,但默认情况下,将所有内容设置为只读通常是一种很好的做法。

答案 1 :(得分:0)

如果属性被注释掉,则返回值为null,因此只需进行空检查。

if (prop.getProperty("name")==null)

如果未填充值,请在修剪操作后检查其是否等于空格。

if (prop.getProperty("name").trim().equals(""))

答案 2 :(得分:0)

在实际使用之前,您可以尝试将属性兑现为静态地图并在该地图上进行处理。

private Map<String, String> rawProps = new HashMap<String, String>;
public static Map<String, String> actualProps = new HashMap<String, String>;

static {
    checkMapForNullAndReport();
}

private static void checkMapForNullAndReport() {
    // Null logic and Reporting logic
    // Empty rawProps and populate the actualProps
}

像我这样的东西对你有用。