Pulling values from a Java Properties file in order?

前端 未结 15 653
庸人自扰
庸人自扰 2020-12-02 18:32

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

相关标签:
15条回答
  • 2020-12-02 19:15

    Apache Commons Configuration might 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:

    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();
        }
    }
    
    0 讨论(0)
  • 2020-12-02 19:17

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

    OrderedProperties properties = new OrderedProperties();
    properties.load(new FileInputStream(new File("~/some.properties")));
    
    0 讨论(0)
  • 2020-12-02 19:18

    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

    0 讨论(0)
  • 2020-12-02 19:19

    In some answers it is assumed that properties read from file are put to instance of Properties (by calls to put) in order they appear they in file. While this is in general how it behaves I don't see any guarantee for such order.

    IMHO: it is better to read the file line by line (so that the order is guaranteed), than use the Properties class just as a parser of single property line and finally store it in some ordered Collection like LinkedHashMap.

    This can be achieved like this:

    private LinkedHashMap<String, String> readPropertiesInOrderFrom(InputStream propertiesFileInputStream)
                                                               throws IOException {
        if (propertiesFileInputStream == null) {
          return new LinkedHashMap(0);
        }
    
        LinkedHashMap<String, String> orderedProperties = new LinkedHashMap<String, String>();
    
        final Properties properties = new Properties(); // use only as a parser
        final BufferedReader reader = new BufferedReader(new InputStreamReader(propertiesFileInputStream));
    
        String rawLine = reader.readLine();
    
        while (rawLine != null) {
          final ByteArrayInputStream lineStream = new ByteArrayInputStream(rawLine.getBytes("ISO-8859-1"));
          properties.load(lineStream); // load only one line, so there is no problem with mixing the order in which "put" method is called
    
    
          final Enumeration<?> propertyNames = properties.<String>propertyNames();
    
          if (propertyNames.hasMoreElements()) { // need to check because there can be empty or not parsable line for example
    
            final String parsedKey = (String) propertyNames.nextElement();
            final String parsedValue = properties.getProperty(parsedKey);
    
            orderedProperties.put(parsedKey, parsedValue);
            properties.clear(); // make sure next iteration of while loop does not access current property
          }
    
          rawLine = reader.readLine();
        }
    
        return orderedProperties;
    
      }
    

    Just note that the method posted above takes an InputStream which should be closed afterwards (of course there is no problem to rewrite it to take just a file as an argument).

    0 讨论(0)
  • 2020-12-02 19:21

    Working example :

    Map<String,String> properties = getOrderedProperties(new FileInputStream(new File("./a.properties")));
    properties.entrySet().forEach(System.out::println);
    

    Code for it

    public Map<String, String> getOrderedProperties(InputStream in) throws IOException{
        Map<String, String> mp = new LinkedHashMap<>();
        (new Properties(){
            public synchronized Object put(Object key, Object value) {
                return mp.put((String) key, (String) value);
            }
        }).load(in);
        return mp;
    }
    
    0 讨论(0)
  • 2020-12-02 19:22

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

    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.

    Thanks Dominique!

    0 讨论(0)
提交回复
热议问题