如何使用排序键将java.util.Properties写入XML?

时间:2020-03-05 18:50:48  来源:igfitidea点击:

我想将属性文件存储为XML。这样做时是否有一种方法可以对键进行排序,以使生成的XML文件按字母顺序排列?

String propFile = "/path/to/file";
Properties props = new Properties();
/*set some properties here*/
try {
    FileOutputStream xmlStream = new FileOutputStream(propFile);
    /*this comes out unsorted*/
    props.storeToXML(xmlStream,"");
} catch (IOException e) {
    e.printStackTrace();
}

解决方案

回答

java.util.Properties基于Hashtable,它不按字母顺序存储其值,而是按每个项目的哈希顺序存储,这就是为什么我们看到自己的行为。

回答

java.util.Properties是java.util.Hashtable的子类。 ("哈希"是这里的关键。)我们必须基于保持/定义订单的东西(例如TreeMap)提出自己的客户实现。

回答

我们可以先对键进行排序,然后循环遍历属性文件中的项目并将其写入xml文件。

public static void main(String[] args){
        String propFile = "/tmp/test2.xml";
        Properties props = new Properties();
        props.setProperty("key", "value");
        props.setProperty("key1", "value1");
        props.setProperty("key2", "value2");
        props.setProperty("key3", "value3");
        props.setProperty("key4", "value4");

        try {
            BufferedWriter out = new BufferedWriter(new FileWriter(propFile));
            List<String> list = new ArrayList<String>();
            for(Object o : props.keySet()){
                list.add((String)o);
            }
            Collections.sort(list);
            out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
            out.write("<!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\">\n");
            out.write("<properties>\n");
            out.write("<comment/>\n");
            for(String s : list){
                out.write("<entry key=\"" + s + "\">" + props.getProperty(s) + "</entry>\n");
            }
            out.write("</properties>\n");
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

回答

我们可以尝试以下方法:

创建一个新类,其功能与java.util.XMLUtils相同,但是在save方法中将其更改为:

Set keys = props.keySet();
Iterator i = keys.iterator();

Set keys = props.keySet();
List<String> newKeys = new ArrayList<String>();
for(Object key : keys)
{
   newKeys.add(key.toString());
}
Collections.sort(newKeys);
Iterator i = newKeys.iterator();

扩展属性并覆盖Properties类的storeToXML方法,以调用新类的save方法。

回答

为什么要首先对XML文件进行排序?大概还有一段代码读取文件并将数据放入另一个Properties对象。我们是否要执行此操作,以便可以手动查找和编辑XML文件中的条目?

回答

最简单的方法是重写keySet。有点hack,并且不能保证可以在将来的实现中使用:

new Properties() {
    @Override Set<Object> keySet() {
        return new TreeSet<Object>(super.keySet());
    }
}

(免责声明:我什至没有测试过它可以编译。)

另外,我们可以使用XSLT之类的格式来重新格式化生成的XML。

回答

这是一种快速而肮脏的方法:

String propFile = "/path/to/file";
Properties props = new Properties();
/*set some properties here*/
Properties tmp = new Properties() {

  @Override
  public Set<Object> keySet()
  {
    return Collections.unmodifiableSet(new TreeSet<Object>(super.keySet()));
  }

};
tmp.putAll(props);
try {
    FileOutputStream xmlStream = new FileOutputStream(propFile);
    /*this comes out SORTED! */
    tmp.storeToXML(xmlStream,"");
} catch (IOException e) {
    e.printStackTrace();
}

注意事项:

  • tmp属性(匿名子类)不满足属性合同。

例如,如果我们获取了它的keySet并试图从其中删除一个元素,则会引发异常。因此,不要让此子类的实例转义!在上面的代码段中,我们永远不会将其传递给另一个对象,也不会将其返回给有合理预期会履行Properties合同的调用方,因此这是安全的。

  • Properties.storeToXML的实现可能会更改,导致其忽略keySet方法。

例如,将来的发行版或者OpenJDK可以使用Hashtable的keys()方法代替keySet。这就是类应该始终记录其"自用"的原因之一(有效的Java项目15)。但是,在这种情况下,发生的最坏情况是输出将恢复为未排序。

  • 请记住,属性存储方法将忽略所有"默认"条目。

回答

这是一种为商店Properties.store(OutputStream out,字符串注释)和`Properties.storeToXML(OutputStream os,字符串注释)产生排序输出的方法:

Properties props = new Properties() {
    @Override
    public Set<Object> keySet(){
        return Collections.unmodifiableSet(new TreeSet<Object>(super.keySet()));
    }

    @Override
    public synchronized Enumeration<Object> keys() {
        return Collections.enumeration(new TreeSet<Object>(super.keySet()));
    }
};
props.put("B", "Should come second");
props.put("A", "Should come first");
props.storeToXML(new FileOutputStream(new File("sortedProps.xml")), null);
props.store(new FileOutputStream(new File("sortedProps.properties")), null);