按顺序从 Java 属性文件中提取值?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1312383/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 08:07:10  来源:igfitidea点击:

Pulling values from a Java Properties file in order?

javaconfigurationpropertiesmaps

提问by James McMahon

I have a properties file where the order of the values is important. I want to be able to iterate through the properties file and output the values based on the order of the original file.

我有一个属性文件,其中值的顺序很重要。我希望能够遍历属性文件并根据原始文件的顺序输出值。

However, since the Properties file is backed by, correct me if I'm wrong, a Map that does not maintain insertion order, the iterator returns the values in the wrong order.

但是,由于 Properties 文件支持,如果我错了,请纠正我,一个不维护插入顺序的 Map,迭代器以错误的顺序返回值

Here is the code I'm using

这是我正在使用的代码

Enumeration names = propfile.propertyNames();
while (names.hasMoreElements()) {
    String name = (String) names.nextElement();
    //do stuff
}

Is there anyway to get the Properties back in order short of writting my own custom file parser?

无论如何,为了不编写我自己的自定义文件解析器,是否可以恢复属性?

采纳答案by Clint

If you can alter the property names your could prefix them with a numeral or other sortable prefix and then sort the Properties KeySet.

如果您可以更改属性名称,则可以使用数字或其他可排序前缀作为前缀,然后对属性键集进行排序。

回答by Jon Skeet

Nope - maps are inherently "unordered".

不 - 地图本质上是“无序的”。

You could possiblycreate your own subclass of Propertieswhich overrode setPropertyand possibly put, but it would probably get very implementation-specific... Propertiesis a prime example of bad encapsulation. When I last wrote an extended version (about 10 years ago!) it ended up being hideous and definitely sensitive to the implementation details of Properties.

您可能创建自己的子类,Properties其覆盖setProperty和可能put,但它可能会变得非常特定于实现......Properties是不良封装的一个主要例子。当我上次编写扩展版本时(大约 10 年前!)它最终变得可怕并且对Properties.

回答by serg

Apache Commons Configurationmight do the trick for you. I haven't tested this myself, but I checked their sources and looks like property keys are backed by LinkedList in AbstractFileConfiguration class:

Apache Commons Configuration可能会为您解决问题。我自己还没有测试过这个,但我检查了他们的来源,看起来属性键是由 AbstractFileConfiguration 类中的 LinkedList 支持的:

public Iterator getKeys()
{
    reload();
    List keyList = new LinkedList();
    enterNoReload();
    try
    {
        for (Iterator it = super.getKeys(); it.hasNext();)
        {
            keyList.add(it.next());
        }

        return keyList.iterator();
    }
    finally
    {
        exitNoReload();
    }
}

回答by Dominique Laurent

Extend java.util.Properties, override both put()and keys():

扩展java.util.Properties,覆盖put()keys()

import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Properties;
import java.util.HashMap;

public class LinkedProperties extends Properties {
    private final HashSet<Object> keys = new LinkedHashSet<Object>();

    public LinkedProperties() {
    }

    public Iterable<Object> orderedKeys() {
        return Collections.list(keys());
    }

    public Enumeration<Object> keys() {
        return Collections.<Object>enumeration(keys);
    }

    public Object put(Object key, Object value) {
        keys.add(key);
        return super.put(key, value);
    }
}

回答by KonstantinSpirov

You must override also keySet() if you want to export Properties as XML:

如果要将属性导出为 XML,还必须覆盖 keySet():

public Set<Object> keySet() { return keys; }

public Set<Object> keySet() { return keys; }

回答by Noah

Dominique Laurent's solution above works great for me. I also added the following method override:

Dominique Laurent 上面的解决方案对我很有用。我还添加了以下方法覆盖:

public Set<String> stringPropertyNames() {
    Set<String> set = new LinkedHashSet<String>();

    for (Object key : this.keys) {
        set.add((String)key);
    }

    return set;
}

Probably not the most efficient, but it's only executed once in my servlet lifecycle.

可能不是最有效的,但它在我的 servlet 生命周期中只执行一次。

Thanks Dominique!

谢谢多米尼克!

回答by qwerty

In the interest of completeness ...

为了完整性......

public class LinkedProperties extends Properties {

    private final LinkedHashSet<Object> keys = new LinkedHashSet<Object>();

    @Override
    public Enumeration<?> propertyNames() {
        return Collections.enumeration(keys);
    }

    @Override
    public synchronized Enumeration<Object> elements() {
        return Collections.enumeration(keys);
    }

    public Enumeration<Object> keys() {
        return Collections.enumeration(keys);
    }

    public Object put(Object key, Object value) {
        keys.add(key);
        return super.put(key, value);
    }

    @Override
    public synchronized Object remove(Object key) {
        keys.remove(key);
        return super.remove(key);
    }

    @Override
    public synchronized void clear() {
        keys.clear();
        super.clear();
    }
}

I dont think the methods returning set should be overridden as a set by definition does not maintain insertion order

我不认为返回 set 的方法应该被覆盖,因为 set 根据定义不保持插入顺序

回答by blue-sky

An alternative is just to write your own properties file using LinkedHashMap, here is what I use :

另一种方法是使用 LinkedHashMap 编写自己的属性文件,这是我使用的:

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.LineIterator;

public class OrderedProperties {

    private static Map<String, String> properties = new LinkedHashMap<String, String>();

    private static OrderedProperties instance = null;

    private OrderedProperties() {

    }

    //The propertyFileName is read from the classpath and should be of format : key=value
    public static synchronized OrderedProperties getInstance(String propertyFileName) {
        if (instance == null) {
            instance = new OrderedProperties();
            readPropertiesFile(propertyFileName);
        }
        return instance;
    }

    private static void readPropertiesFile(String propertyFileName){
        LineIterator lineIterator = null;
        try {

            //read file from classpath
            URL url = instance.getClass().getResource(propertyFileName);

            lineIterator = FileUtils.lineIterator(new File(url.getFile()), "UTF-8");
            while (lineIterator.hasNext()) {
                String line = lineIterator.nextLine();

                //Continue to parse if there are blank lines (prevents IndesOutOfBoundsException)
                if (!line.trim().isEmpty()) {
                    List<String> keyValuesPairs = Arrays.asList(line.split("="));
                    properties.put(keyValuesPairs.get(0) , keyValuesPairs.get(1));
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            lineIterator.close();
        }
    }

    public Map<String, String> getProperties() {
        return OrderedProperties.properties;
    }

    public String getProperty(String key) {
        return OrderedProperties.properties.get(key);
    }

}

To use :

使用:

    OrderedProperties o = OrderedProperties.getInstance("/project.properties");
    System.out.println(o.getProperty("test"));

Sample properties file (in this case project.properties) :

示例属性文件(在本例中为 project.properties):

test=test2

回答by Etienne Studer

See https://github.com/etiennestuder/java-ordered-propertiesfor a complete implementation that allows to read/write properties files in a well-defined order.

请参阅https://github.com/etiennestuder/java-ordered-properties以获取允许以明确定义的顺序读取/写入属性文件的完整实现。

OrderedProperties properties = new OrderedProperties();
properties.load(new FileInputStream(new File("~/some.properties")));

回答by Campa

I'll add one more famous YAEOOJP (Yet Another Example Of Ordered Java Properties) to this thread because it seems nobody could ever care less about defaultproperties which you can feed to your properties.

我将在此线程中添加一个更著名的 YAEOOJP(又一个有序 Java 属性示例),因为似乎没有人会关心您可以提供给属性的默认属性。

@see http://docs.oracle.com/javase/tutorial/essential/environment/properties.html

@see http://docs.oracle.com/javase/tutorial/essential/environment/properties.html

That's my class: surely not 1016% compliant with any possible situation, but that is fine for my limited dumb purposes right now. Any further comment for correction is appreciated so the Greater Good can benefit.

那是我的班级:肯定不是 10 16% 符合任何可能的情况,但这对于我现在有限的愚蠢目的来说很好。感谢您对更正的任何进一步评论,以便上善会受益。

import java.util.Collections;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

/**
 * Remember javadocs  >:o
 */
public class LinkedProperties extends Properties {

    protected LinkedProperties linkedDefaults;
    protected Set<Object> linkedKeys = new LinkedHashSet<>();

    public LinkedProperties() { super(); }

    public LinkedProperties(LinkedProperties defaultProps) {
        super(defaultProps); // super.defaults = defaultProps;
        this.linkedDefaults = defaultProps;
    }

    @Override
    public synchronized Enumeration<?> propertyNames() {
        return keys();
    }

    @Override
    public Enumeration<Object> keys() {
        Set<Object> allKeys = new LinkedHashSet<>();
        if (null != defaults) {
            allKeys.addAll(linkedDefaults.linkedKeys);
        }
        allKeys.addAll(this.linkedKeys);
        return Collections.enumeration(allKeys);
    }

    @Override
    public synchronized Object put(Object key, Object value) {
        linkedKeys.add(key);
        return super.put(key, value);
    }

    @Override
    public synchronized Object remove(Object key) {
        linkedKeys.remove(key);
        return super.remove(key);
    }

    @Override
    public synchronized void putAll(Map<?, ?> values) {
        for (Object key : values.keySet()) {
            linkedKeys.add(key);
        }
        super.putAll(values);
    }

    @Override
    public synchronized void clear() {
        super.clear();
        linkedKeys.clear();
    }

    private static final long serialVersionUID = 0xC00L;
}