编程的时候都要把一些可变的参数放到配置文件里面, 常见的配置文件就是xml, 键值对等. 但是我觉得xml有点大, 浪费; properties这种键值对有点简单了. 就仿照nginx的配置文件格式(不全一样)写了一个配置读取工具. 第一次发代码, 求指导.
首先是配置文件的格式
#注释格式
#system是一个配置段
system {
#子配置段config
config {
#一个配置项
url : localhost
#配置项的值是数组, 用[]包括, 逗号分隔
message : [not login, ok]
}
ok {
#配置项可以只有键(配置项名)而没有值
path1
}
user {
/user
}
whoami : wenjianwzz
}
#也可以不包括在配置段里面
where : cd
然后就是使用方法
public static void main(String args[]) {
//加载配置文件, 返回一个根配置段(文件中所有的)
Config config = Config.load(ResourceUtil.getResourcePath("new.conf"), "UTF-8");
//定位配置, @表示查找配置项, 如果不加@则是查找子配置段
System.out.println(config.locateValue("/system/@whoami"));
//可以用..上翻
System.out.println(config.locateValue("/system/../@where"));
//数组配置的某一值
System.out.println(config.locateValue("/system/config/@message[0]"));
//查找子孙配置段, 不用/打头表示从当前配置段定位, 这里因为本来就是根配置, 所以就一样了
config = config.locateConfig("system/config");
//从当前配置段定位
System.out.println(config.locateValue("@message[0]"));
// 上翻的作用
System.out.println(config.locateValue("../@whoami"));
}
这个用path定位的方式是受xpath启发, 觉得挺好用的
下面就是源码
package eu.jk.config;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import eu.jk.helper.ResourceUtil;
/**
* 配置段类
*
* @author wenjianwzz
*
*/
public final class Config {
/**
* 配置项
*/
private Map<String, ConfigItem> items = new HashMap<String, ConfigItem>();
/**
* 子配置段
*/
private Map<String, Config> subconfigs = new HashMap<String, Config>();
/**
* 父亲
*/
private Config parent = null;
/**
* 配置段名
*/
private String name = null;
/**
* 取得键对应的值,如果不存在对应的值, 返回NULL
*
* @param key
* @return String
* @see java.util.hashtable#get(Object)
*/
public String getValue(String key) {
return items.get(key).getValue();
}
/**
* 取得键对应的值,如果不存在对应的值, 返回NULL
*
* @param key
* @return String
* @see java.util.hashtable#get(Object)
*/
public String getValue(String key, int index) {
return items.get(key).getValue(index);
}
/**
* 查找配置项
* @param key
* @return
*/
public ConfigItem getConfigItem(String key) {
return items.get(key);
}
/**
* 是否包含指定键的配置项
* @param key
* @return
*/
public boolean contains(String key) {
return items.containsKey(key);
}
/**
* 获取所有的配置项名称
* @return
*/
public Collection<String> getItemsKeys() {
return items.keySet();
}
/**
* 获取配置段名
*/
public String getName() {
return name;
}
/**
* 获取所有子配置段的名称
* @return
*/
public Collection<String> getSubconfigKeys() {
return subconfigs.keySet();
}
/**
* 获取子配置段
* @param name
* @return
*/
public Config getSubconfig(String name) {
return subconfigs.get(name);
}
/**
* 是否包含指定名称的子配置段
* @param name
* @return
*/
public boolean containsSubconfig(String name) {
return subconfigs.containsKey(name);
}
/**
* 加载配置项
* @param id
* @return
*/
public ConfigItem locateItem(String id) {
return (ConfigItem) locate(id);
}
/**
* 加载配置值
* @param id
* @return
*/
public String locateValue(String id) {
Object object = locate(id);
if (object == null)
return null;
if (object instanceof ConfigItem)
return ((ConfigItem)object).getValue();
if (object instanceof String)
return (String) object;
return null;
}
/**
* 加载配置项
* @param id
* @return
*/
public Config locateConfig(String id) {
return (Config) locate(id);
}
/**
* 加载
* @param id
* @return
*/
protected Object locate(String id) {
if (id == null)
return null;
// 定位基点
Config base = this;
if (id.startsWith("/"))
while (base.getParent() != null)
base = base.getParent();
String[] fields = id.split("/");
for (String field : fields) {
field = field.trim();
if ("".equals(field))
continue;
if (field.startsWith("@")) {
if (field.matches("^@.+\\[[0-9]+\\]$")) {
String key = field.substring(1, field.indexOf('['));
String index = field.substring(field.indexOf('[') + 1, field.indexOf(']'));
if (!isDigit(index))
return null;
return base.getConfigItem(key).getValue(Integer.parseInt(index));
}
return base.getConfigItem(field.substring(1));
}
if ("..".equals(field))
base = base.getParent();
else
base = base.getSubconfig(field);
if (base == null)
return null;
}
return base;
}
/**
* 添加参数, 如果原来存在参数, 会接在后面成为一个数组
*
* @param key
* @param value
*/
protected void addParameters(String key, String value) {
ConfigItem item = items.get(key);
if (item == null)
items.put(key, new ConfigItem(key, value));
else
item.addValue(value);
}
protected void setConfigName(String configName) {
this.name = configName;
}
protected Config(String configName) {
this.name = configName;
}
/**
* 添加子配置段
* @param subconfig
*/
protected void addSubconfig(Config subconfig) {
subconfig.setConfigName(subconfig.getName().trim());
subconfigs.put(subconfig.getName(), subconfig);
}
protected void setParent(Config parent) {
this.parent = parent;
}
protected Config getParent() {
return parent;
}
/**
* 加载配置文件, 返回根配置段
* @param path 配置文件的路径
* @param encoding 文件编码, 如果为null则使用系统默认编码
* @return 根配置
*/
public static Config load(String path, String encoding) {
try {
return load(new FileInputStream(path), encoding, path);
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
}
}
/**
* 使用系统默认编码加载配置文件, 返回根配置
* @param path 配置文件的路径
* @return 根配置
*/
public static Config load(String path) {
return load(path, null);
}
/**
* 从流中加载配置, 使用系统默认编码
* @param input 输入流
* @param rootConfigName 根配置名
* @return
*/
public static Config load(InputStream input, String rootConfigName) {
return load(input, null, rootConfigName);
}
/**
* 从流中加载配置, 使用系统默认编码
* @param input 输入流
* @return 根配置
*/
public static Config load(InputStream input) {
return load(input, null, "anonymous");
}
/**
* 从流中加载配置, 使用指定编码
* @param input 输入流
* @param encoding 编码
* @param rootConfigName 根配置名
* @return 根配置
*/
public static Config load(InputStream input, String encoding, String rootConfigName) {
Config root = new Config(rootConfigName);
for (String line : readLines(input, encoding)) {
line = line.trim();
if (line.startsWith("#"))
continue;
if (line.length() == 0)
continue;
//SubConfig found
if (line.matches("^.+\\{$")) {
String name = new String(line.replace('{', '\b').trim());
Config sub = new Config(name);
root.addSubconfig(sub);
sub.setParent(root);
root = sub;
continue;
}
/*
* 往上翻一层
*/
if ("}".equals(line)) {
root = root.getParent();
continue;
}
/*
* 键值对的配置
*/
if (line.contains(":")) {
int index = line.indexOf(':');
String key = line.substring(0, index).trim();
String value = line.substring(index + 1).trim();
if (value.matches("^\\[.+\\]$")) {
value = value.substring(1, value.length()-1);
for (String sub : value.split(",")) {
sub = sub.trim();
if (sub.length() == 0)
continue;
root.addParameters(key, sub);
}
continue;
}
root.addParameters(key, value);
continue;
}
root.addParameters(line, null);
}
return root;
}
/**
* 判断一个字符串是不是数字
* @param str
* @return boolean
*/
private static boolean isDigit(String str) {
if (str == null)
return false;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (c < 48 || c > 57)
return false;
}
return true;
}
/**
* 从流中读取所有行
* @param path
* @param encoding
* @return
*/
private static List<String> readLines(InputStream input, String encoding) {
InputStreamReader fr;
List<String> list = new ArrayList<String>();
try {
if (encoding != null)
fr = new InputStreamReader(input, encoding);
else
fr = new InputStreamReader(input);
BufferedReader br = new BufferedReader(fr);
String line = br.readLine();
while (line != null) {
list.add(line);
line = br.readLine();
}
br.close();
fr.close();
} catch (Exception e) {
e.printStackTrace();
return null;
}
return list;
}
public static void main(String args[]) {
//加载配置文件, 返回一个根配置段(文件中所有的)
Config config = Config.load(ResourceUtil.getResourcePath("new.conf"), "UTF-8");
//定位配置, @表示查找配置项, 如果不加@则是查找子配置段
System.out.println(config.locateValue("/system/@whoami"));
//可以用..上翻
System.out.println(config.locateValue("/system/../@where"));
//数组配置的某一值
System.out.println(config.locateValue("/system/config/@message[0]"));
//查找子孙配置段, 不用/打头表示从当前配置段定位, 这里因为本来就是根配置, 所以就一样了
config = config.locateConfig("system/config");
//从当前配置段定位
System.out.println(config.locateValue("@message[0]"));
// 上翻的作用
System.out.println(config.locateValue("../@whoami"));
}
}
package eu.jk.config;
import java.util.ArrayList;
import java.util.List;
/**
* 配置项
* @author WZZ
*
*/
public final class ConfigItem {
String key;
List<String> values = new ArrayList<String>();
protected ConfigItem(String key) {
this.key = key;
}
protected ConfigItem(String key, String value) {
this.key = key;
values.add(value);
}
protected void addValue(String value) {
values.add(value);
}
public String getKey() {
return key;
}
public String getValue() {
if (values.size() <= 0)
return null;
return values.get(0);
}
public String getValue(int index) {
if (values.size() <= index || index < 0)
return null;
return values.get(index);
}
public int size() {
return values.size();
}
}