论坛首页 Java企业应用论坛

写了一个配置文件读取工具, 分享. 欢迎拍砖

浏览 6955 次
精华帖 (0) :: 良好帖 (2) :: 新手帖 (0) :: 隐藏帖 (2)
作者 正文
   发表时间:2011-12-23  

编程的时候都要把一些可变的参数放到配置文件里面, 常见的配置文件就是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();
	}
}
 
   发表时间:2011-12-23  
-一般?喜欢用commons configuration
0 请登录后投票
   发表时间:2011-12-24  
nginx conf 应该可以叫dsl了吧
0 请登录后投票
   发表时间:2011-12-24  
直接变成json貌似也挺方便的,用JSONObject反序列化一下就行了
0 请登录后投票
   发表时间:2011-12-25  
没发现任何好处,比 properties 配置文件能小点?但代码可多了不少
0 请登录后投票
   发表时间:2011-12-25  
if (field.matches("^@.+\\[[0-9]+\\]$")) {  
178.                    String key = field.substring(1, field.indexOf('['));  
179.                    String index = field.substring(field.indexOf('[') + 1, field.indexOf(']'));  
180.                    if (!isDigit(index))  
181.                        return null;  
182.                    return base.getConfigItem(key).getValue(Integer.parseInt(index));  
183.                }  
184.                return base.getConfigItem(field.substring(1));  
//先看看java正则,这段代码没这么复杂 直接group就能拿到
0 请登录后投票
   发表时间:2011-12-25  
请问楼主,xml如何浪费了?
0 请登录后投票
   发表时间:2011-12-26  
ResourceBundle读不方便吗?
0 请登录后投票
   发表时间:2011-12-26  
不评价                
0 请登录后投票
   发表时间:2011-12-26  
weiqiang.yang 写道
直接变成json貌似也挺方便的,用JSONObject反序列化一下就行了

这个法子好
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics