欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Properties类按顺序输出加载内容

程序员文章站 2022-04-14 15:43:22
Properties类按顺序输出加载内容 最近手写工厂的时候,遇到了加载配置文件时不按照properties文件中的数据的顺序来加载。 一、问题代码 配置文件 输出结果 二、原因分析 上面是Properties类的定义,可以看到它继承了Hashtable类 load方法调用load0方法 方法: H ......

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

输出结果

Properties类按顺序输出加载内容

二、原因分析

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;
    }
}

四、结果测试

Properties类按顺序输出加载内容