我的任务是工作中的任务,需要持久的客户端设置。这些设置由我正在实现的框架的C#版本中的XML文件表示,它表示具有最多六层的层次结构的对象。此外,不同级别中的对象数有时是任意的,如ArrayList。遗憾的是,对象序列化不是一种选择,因为需要能够直接编辑文件。我不得不将这些设置的持久性实现为.properties文件,但我对这是否是一个好主意感到担忧。
据我所知,.properties文件只能以与HashMap相同的方式使用,只有字符串的键值配对。复杂对象的表示似乎只能用长而复杂的关键字符串表示,它代表每个元素的整个“路径”,包括它可能在几个列表中的单个索引。
filters.filter3.traces.rule4.add1.value="8"
我无法找到任何合适的方法来在.properties文件中保留分层对象,但我也无法找到任何明确的证据证明它不可能。
那么,.properties文件是否适合存储分层设置 - 对象?或者我应该将我的属性实现为XML文件还是JSON?
答案 0 :(得分:1)
我会坚持使用XML文件。没有什么比使用API框架的不同变体的不同格式更能激怒用户。
您可以使用Apache XMLBeans等库来简化读取和写入XML文件的过程,使用模式文件自动生成适当的Java类。
属性文件可用于存储分层数据,但手动编辑这些内容真的很痛苦,并且很容易引入错误。有些人认为XML编辑也不是轻而易举,但至少存在编辑器可以在与XSD链接时更容易编辑。
答案 1 :(得分:1)
我总是发现这种存储分层配置数据的方式非常麻烦,但它很有可能。例如,它(曾经是?)是配置Log4j的最常用方式,但根据我的经验,越来越多的开发人员也在这里切换到XML。
我真的没有看到为此目的使用属性文件的重点。
答案 2 :(得分:1)
我认为你已经掌握了它的要点 - Java属性文件可以表达层次结构,但是很笨拙。
查看Typesafe Config library,这是Play Framework使用的内容。它的主要语言是HOCON(人工优化配置符号),它非常适合表达层次结构属性。该库还可以兼容属性文件和JSON,因此您可以轻松地同时支持所有这些语言。
在Java属性文件中,正如您所说,您仅限于使用虚线键
a.b.c = 42
在HOCON中,您可以选择执行此操作或使用花括号嵌套部分。因此,该示例可以通过以下任何方式表达:
a.b.c : 42
a {
b.c : 42
}
a.b {
c : 42
}
a {
b {
c : 42
}
}
答案 3 :(得分:1)
您有一个log4j
形式的完美示例:此处是来自here的属性示例。
log4j.appender.R = org.apache.log4j.DailyRollingFileAppender
log4j.appender.R.File = logs/bensApps.log
log4j.appender.R.Append = true
log4j.appender.R.DatePattern = '.'yyy-MM-dd
log4j.appender.R.layout = org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} %c{1} [%p] %m%n
如果您在这些键中有层次结构,例如:
Map<String,Object> root = new HashMap<>();
root.put("level1", "foobar");
root.put("level2", Collections.singletonMap("p", "foobar");
您可以将其翻译成:
level1=foobar
level2.p=foobar
在阅读文件时,将.
拆分为子图:
Map<String, Object> root = new HashMap<>();
Properties propz = new Properties();
// load from your file
for (Map.Entry<String,Object> entry : propz.entrySet()) {
String[] path = entry.getKey().split('\\.');
Map<String,Object> parent = root;
int n = path.length - 1;
for (int i = 0; i < n; ++i) {
String p = path[i];
Object child = parent.get(p);
if (null == child) {
Map<String,Object> _p = new HashMap<>();
parent.put(p, _p);
parent = _p;
} else if (child instanceof Map) {
parent = (Map<String,Objext>) child;
} else {
// it is up to you to do something when the path extends beyond a "final" key
}
}
parent.put(path[n], entry.getValue());
}
然而,这是一个&#34;重新发明轮子&#34;模式,其他答案指出你可能比自己做更好的解决方案。这个例子也向您展示了一种问题:
p1=foobar
p1.p2=foobar
在机器生成属性的情况下,这不会发生,并且异常可能是最佳答案。但在人为操纵属性的情况下,这可能有一些意义。
另一方面,由于Java 7附带了JAXB,您也可以使用完整的XML来完成,而无需额外的库。并使用某种层次结构。