文档章节

Properties类按顺序输出加载内容

o
 osc_wws45aot
发布于 2019/08/20 12:27
字数 656
阅读 9
收藏 0

精选30+云产品,助力企业轻松上云!>>>

Properties类按顺序输出加载内容

最近手写工厂的时候,遇到了加载配置文件时不按照properties文件中的数据的顺序来加载。

一、问题代码

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class PropertiesTest {
    public static void main(String[] args) {
        InputStream ips = null;
        try {
            ips = Properties.class.getResourceAsStream("/test.properities");
            Properties props = new Properties();
            props.load(ips);
            for(String name:props.stringPropertyNames())
                System.out.println(props.getProperty(name) + " "+name);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if(ips != null){
                    ips.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

配置文件

cat=1
dog=2
bird=3
mouse=4
pig=5

输出结果

二、原因分析

public class Properties extends Hashtable<Object,Object>

上面是Properties类的定义,可以看到它继承了Hashtable类

public synchronized void load(InputStream inStream) throws IOException {
        load0(new LineReader(inStream));
    }

load方法调用load0方法

private void load0 (LineReader lr) throws IOException {
        char[] convtBuf = new char[1024];
        int limit;
        int keyLen;
        int valueStart;
        char c;
        boolean hasSep;
        boolean precedingBackslash;

        while ((limit = lr.readLine()) >= 0) {
            c = 0;
            keyLen = 0;
            valueStart = limit;
            hasSep = false;

            //System.out.println("line=<" + new String(lineBuf, 0, limit) + ">");
            precedingBackslash = false;
            while (keyLen < limit) {
                c = lr.lineBuf[keyLen];
                //need check if escaped.
                if ((c == '=' ||  c == ':') && !precedingBackslash) {
                    valueStart = keyLen + 1;
                    hasSep = true;
                    break;
                } 
                else if ((c == ' ' || c == '\t' ||  c == '\f') && !precedingBackslash) 					{
                    valueStart = keyLen + 1;
                    break;
                }
                if (c == '\\') {
                    precedingBackslash = !precedingBackslash;
                } else {
                    precedingBackslash = false;
                }
                keyLen++;
            }
            while (valueStart < limit) {
                c = lr.lineBuf[valueStart];
                if (c != ' ' && c != '\t' &&  c != '\f') {
                    if (!hasSep && (c == '=' ||  c == ':')) {
                        hasSep = true;
                    } else {
                        break;
                    }
                }
                valueStart++;
            }
            String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);
            String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);
            put(key, value);
        }
    }

load0方法可以看到最后取到key和value值后会调用父类Hashtable的put()方法,把数据存入Hashtable,具体的Hashtable源码这里就不再贴出。简单来说Hashtable的put()方法接收到值后会按照哈希值存储,而不是按照读取顺序存储。

接下来是读取时的源码,有兴趣的可以看一下:

public Set<String> stringPropertyNames() {
        Hashtable<String, String> h = new Hashtable<>();
        enumerateStringProperties(h);
        return h.keySet();
    }

enumerateStringProperties方法:

private synchronized void enumerateStringProperties(Hashtable<String, String> h) {
        if (defaults != null) {
            defaults.enumerateStringProperties(h);
        }
        for (Enumeration<?> e = keys() ; e.hasMoreElements() ;) {
            Object k = e.nextElement();
            Object v = get(k);
            if (k instanceof String && v instanceof String) {
                h.put((String) k, (String) v);
            }
        }
    }

Hashtable的keySet()方法

public Set<K> keySet() {
        if (keySet == null)
            keySet = Collections.synchronizedSet(new KeySet(), this);
        return keySet;
    }

三、解决方法

写一个工具类继承Properties类,实现以下功能:

  1. 创建一个能够按照读取顺序来存储properities文件中的key值的集合框架
  2. 能够返回步骤1创建的集合

在这里我采用了LinkedList来顺序存储key值(也可以采用别的集合类型),然后重写put方法,先把值存入自己建的LinkedList中,再调用父类的方法。关于返回Key值的集合是新写了一个orderStringPropertyNames()方法返回LinkedList

实现代码如下:

import java.util.LinkedList;
import java.util.Properties;

public class LinkedProperities extends Properties {

    private LinkedList<String> linkedList = new LinkedList<String>();



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


    public LinkedList<String> orderStringPropertyNames() {
        return linkedList;
    }
}

四、结果测试

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。

暂无文章

SnailSVN Pro for mac(SVN客户端) v1.9.9

macw为您带来SnailSVN Pro for mac ,SnailSVN Mac版是一款类似于 TortoiseSVN 的 Apache Subversion(SVN)客户端,与 Finder 紧密集成。SnailSVN Mac版允许你从 Finder 的上下文菜单中快速...

单手绕月
33分钟前
13
0
python网络编程(进程与多线程)

multiprocessing模块   由于GIL的存在,python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大部分情况需要使用多进程。   multiprocessing包是Pytho...

osc_ky74f26k
33分钟前
5
0
CentOS7 redis5.0高可用部署

概述 Redis Sentinel为Redis提供高可用性。Redis Sentinel是一个分布式系统,Sentinel本身设计为在有多个Sentinel进程协同合作的配置中运行。具有多个Sentinel进程进行协作的优点如下: 1、当...

紅顏為君笑
33分钟前
12
0
Ocelot简易教程(四)之请求聚合以及服务发现

上篇文章给大家讲解了Ocelot的一些特性并对路由进行了详细的介绍,今天呢就大家一起来学习下Ocelot的请求聚合以及服务发现功能。希望能对大家有所帮助。 作者:依乐祝 原文地址:https://www...

osc_zo0djpuu
34分钟前
14
0
leetcode63(不同路径 II)--Java语言实现

求: 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 现在...

拓拔北海
34分钟前
15
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部