假设我们有一个配置文件config.properties,取自APDPlat的主配置文件:
#主配置文件 #是否启用WEB目录文件增加和删除监控 watch.directory.enable=true #用户密码安全策略 user.password.strategy=passwordLengthStrategy;passwordComplexityStrategy #如果启用数据库配置,则数据库中的配置信息有最高优先级,会覆盖配置文件的配置信息 config.db.enable=true #用配置文件中的信息强行覆盖数据库中的配置信息 config.db.override=false #使用哪一个模块,数据库配置中会用到此变量 module.short.name=apdplat
我们怎么写程序解析呢?很多人会告诉你使用java.util.Properties:
首先,准备容器:Properties props = new Properties();
其次,准备资源:ClassPathResource cr = new ClassPathResource("/org/apdplat/config.properties");
再次,加载资源:props.load(cr.getInputStream());
最后,使用配置:String value = props.getProperty(“watch.directory.enable”);
但是这种方式真的好吗?上面的步骤中,如果配置项包含中文,我们在加载资源之前还要执行一个步骤,执行命令:
native2ascii config.properties
用命令生成的结果来替换原来的配置:
#\u4e3b\u914d\u7f6e\u6587\u4ef6 #\u662f\u5426\u542f\u7528WEB\u76ee\u5f55\u6587\u4ef6\u589e\u52a0\u548c\u5220\u9664\u76d1\u63a7 watch.directory.enable=true #\u7528\u6237\u5bc6\u7801\u5b89\u5168\u7b56\u7565 user.password.strategy=passwordLengthStrategy;passwordComplexityStrategy #\u5982\u679c\u542f\u7528\u6570\u636e\u5e93\u914d\u7f6e\uff0c\u5219\u6570\u636e\u5e93\u4e2d\u7684\u914d\u7f6e\u4fe1\u606f\u6709\u6700\u9ad8\u4f18\u5148\u7ea7\uff0c\u4f1a\u8986\u76d6\u914d\u7f6e\u6587\u4ef6\u7684\u914d\u7f6e\u4fe1\u606f config.db.enable=true #\u7528\u914d\u7f6e\u6587\u4ef6\u4e2d\u7684\u4fe1\u606f\u5f3a\u884c\u8986\u76d6\u6570\u636e\u5e93\u4e2d\u7684\u914d\u7f6e\u4fe1\u606f config.db.override=false #\u4f7f\u7528\u54ea\u4e00\u4e2a\u6a21\u5757\uff0c\u6570\u636e\u5e93\u914d\u7f6e\u4e2d\u4f1a\u7528\u5230\u6b64\u53d8\u91cf module.short.name=apdplat
可以看到,我们所有的中文注释都被转码了,我们人可看不懂啥意思啊,那怎么还原呢?看如下命令:
native2ascii config.properties | native2ascii -reverse
通过这个命令的输出你就知道,可以使用native2ascii -reverse命令来还原,但是,配置文件的好处就在于方便修改配置,现在被转换成这样,是不是很糟糕呢?肯定是了,那么怎么办呢?我们可以先还原原来的文本,然后把文本文件保存为utf-8格式,接着改变加载资源的方式,指定文件编码:
props.load(new InputStreamReader(cr.getInputStream(), "utf-8"));
这样就解决了。
更进一步,如果我们不用JDK内置的Properties,要自己实现,我们该如何编写配置文件解析程序呢?
我们使用UTF-8编码的普通文本文件,不用转码,在内存中使用HashMap来保存配置信息,如下代码所示,来自APDPlat的PropertyHolder类:
package org.apdplat.module.system.service; import org.apdplat.platform.log.APDPlatLogger; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Locale; import java.util.Map; import org.apdplat.platform.log.APDPlatLoggerFactory; import org.springframework.core.io.ClassPathResource; /** * 系统配置 * @author 杨尚川 */ public class PropertyHolder { private static final APDPlatLogger LOG = APDPlatLoggerFactory.getAPDPlatLogger(PropertyHolder.class); private static final Map<String, String> PROPERTIES = new HashMap<>(); static { init(); } public static Map<String, String> getProperties() { return PROPERTIES; } private static void load(InputStream inputStream, Map<String, String> map){ try(BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"))){ String line; while((line = reader.readLine()) != null){ line = line.trim(); if("".equals(line) || line.startsWith("#")){ continue; } int index = line.indexOf("="); if(index==-1){ LOG.error("错误的配置:"+line); continue; } if(index>0 && line.length()>index+1) { String key = line.substring(0, index).trim(); String value = line.substring(index + 1, line.length()).trim(); map.put(key, value); }else{ LOG.error("错误的配置:"+line); } } } catch (IOException ex) { LOG.error("配置文件加载失败:" + ex.getMessage()); throw new RuntimeException(ex); } } /** * 本方法中的日志只能输出中文,因为APDPlatLoggerImpl中默认指定输出中文 * 只有配置项加载完毕,调用了指定日志输出语言方法LOG.setLocale(getLogLanguage()) * 之后,配置的日志输出语言才会生效 */ private static void init() { String systemConfig="/org/apdplat/config.properties"; String localConfig="/config.local.properties"; String dbConfig="/org/apdplat/db.properties"; String localDBConfig="/db.local.properties"; ClassPathResource cr = null; try{ cr = new ClassPathResource(systemConfig); load(cr.getInputStream(), PROPERTIES); LOG.info("装入主配置文件:"+systemConfig); }catch(Exception e){ LOG.info("装入主配置文件"+systemConfig+"失败!", e); } try{ cr = new ClassPathResource(localConfig); load(cr.getInputStream(), PROPERTIES); LOG.info("装入自定义主配置文件:"+localConfig); }catch(Exception e){ LOG.info("装入自定义主配置文件"+localConfig+"失败!", e); } try{ cr = new ClassPathResource(dbConfig); load(cr.getInputStream(), PROPERTIES); LOG.info("装入数据库配置文件:"+dbConfig); LOG.info("Database profile is loaded:"+dbConfig); }catch(Exception e){ LOG.info("装入数据库配置文件"+dbConfig+"失败!", e); } try{ cr = new ClassPathResource(localDBConfig); load(cr.getInputStream(), PROPERTIES); LOG.info("装入自定义数据库配置文件:"+localDBConfig); }catch(Exception e){ LOG.info("装入自定义数据库配置文件"+localDBConfig+"失败!",e); } String extendPropertyFiles = PROPERTIES.get("extend.property.files"); if(extendPropertyFiles!=null && !"".equals(extendPropertyFiles.trim())){ String[] files=extendPropertyFiles.trim().split(","); for(String file : files){ try{ cr = new ClassPathResource(file); load(cr.getInputStream(), PROPERTIES); LOG.info("装入扩展配置文件:"+file); }catch(Exception e){ LOG.info("装入扩展配置文件"+file+"失败!",e); } } } LOG.info("系统配置属性装载完毕"); LOG.info("******************属性列表***************************"); PROPERTIES.keySet().forEach(propertyName -> { LOG.info(" " + propertyName + " = " + PROPERTIES.get(propertyName)); }); LOG.info("***********************************************************"); //指定日志输出语言 LOG.setLocale(getLogLanguage()); } /** * 日志使用什么语言输出 * @return */ public static Locale getLogLanguage(){ String language = getProperty("log.locale.language"); return Locale.forLanguageTag(language); } public static boolean getBooleanProperty(String name) { String value = PROPERTIES.get(name); return "true".equals(value); } public static int getIntProperty(String name) { String value = PROPERTIES.get(name); return Integer.parseInt(value); } public static String getProperty(String name) { String value = PROPERTIES.get(name); return value; } public static void setProperty(String name, String value) { PROPERTIES.put(name, value); } }
相关推荐
通过对该文件的解析,可以看出投资家电行业时,基本面分析与估值分析同样重要。短期市场波动对行业可能造成冲击,但长期来看,具备稳健增长潜力、具有核心竞争力的行业及公司能够在市场调整中找到机会,为投资者提供...
### 技术视角下的化学知识点解析 #### 物质分类与变化分类 - **混合物与纯净物的区别**:从信息技术的角度来看,可以将物质的分类比作数据结构中的简单类型与复合类型。比如,在计算机科学中,一个整数可以被视为...
每张拼图背面都有按顺序排列的数字,但大多数小组未能注意到这一点。 - **知识点解读**: 这部分强调了细致观察对于解决问题的重要性。很多时候,问题的解决方案就隐藏在显而易见的地方,但缺乏仔细观察的习惯可能会...
从给定的文件信息来看,我们正在探讨的是47届国际数学奥林匹克竞赛的题目与解答,这是一项在2006年于斯洛文尼亚举办的全球性数学竞赛,旨在挑战和展示世界各地中学生的数学才能。以下是对部分问题的详细解析: ### ...
根据提供的文件信息,本文将对“lr多个虚拟用户互相访问”的知识点进行详细的解析与扩展,主要涉及LoadRunner(简称LR)中的虚拟用户模拟、rendezvous功能以及文件操作等内容。 ### LoadRunner简介 LoadRunner是...
3. 构建脚本:用于编译和打包游戏的自动化工具,如Maven或Gradle的配置文件。 4. 测试文件:用于确保游戏功能正确性的单元测试和集成测试。 5. 项目配置文件:如IDE的项目设置、版本控制信息等。 玩家在游玩《屠龙...
根据提供的文件信息,我们可以推断出这是一份与Logisim软件相关的实验文档,主要涉及汉字机内码的获取过程。Logisim是一款用于模拟数字逻辑电路设计的软件,广泛应用于计算机科学教育中,帮助学生理解和构建复杂的...
根据给定文件的信息,我们可以从中提炼出以下几个关键的知识点...综上所述,这些知识点涵盖了社会学、国际关系学、经济学以及科技创新等多个领域,不仅有助于理解文件中的具体内容,还能够为我们提供更广阔的思考视角。
当然了,对付验证码也不是一点办法都没有,方法还是有很多的,只是我们需要跳出技术层面去思考问题。 以下是几种常见的解决办法: 1. Debug模式启动浏览器(浏览器复用)(技术) 使用Selenium启动浏览器默认是会...
这个目录可能包含了项目的README文件,用于解释项目目的、如何构建和运行项目,以及其他的源代码文件、资源文件、配置文件等。 基于这些信息,我们可以推测这个项目可能包含以下组件和知识点: 1. **用户界面(UI...
为了改进这一点,可以考虑引入外部配置文件或参数化输入,使程序能够适应不同的音乐作品和演奏风格。 ### 结论 “C++生日歌代码”虽然简短,但蕴含了丰富的教学和实践价值。它不仅是对C++编程能力的一次展示,也是...
项目中的每一个压缩子文件,如"PixelsSounds-main",可能包含了一系列源代码、音频数据、配置文件或者示例图像。源代码是整个项目的核心,它定义了如何解析图像,如何转换像素数据,以及如何生成音乐。音频数据则...
这可能涉及到对数据库或配置文件的管理,其中列出了需要特殊处理的名字,以及相应的替换规则。 从用户角度来看,安装和使用Fame: Replace Celebrity Names-crx插件相对简单。用户只需在浏览器的扩展管理界面安装该...
Fourinone(中文名字“四不像”)是一个四合一分布式计算框架,在写这个框架之前,我对分布式计算进行了长时间的思考,也看了老外写的其他开源框架,当我们把复杂的hadoop当作一门学科学习时,似乎忘记了我们想解决问题...
为了保证这一点,制度要求从招标文件发出至投标文件提交至少需要20天时间,评标则由评标委员会负责,该委员会由不同部门的代表及技术和经济专家组成,保证评标的公正性和专业性。最后,中标后运营改善部要与项目实施...
淘宝Fourinone(中文名字“四不像”)是一个四合一分布式计算框架,在写这个框架之前,我对分布式计算进行了长时间的思考,也看了老外写的其他开源框架,当我们把复杂的hadoop当作一门学科学习时,似乎忘记了我们想...
#### 重要知识点解析: **1. Exadata一体机的企业应用思考** - **选型考量因素**:企业在选择Oracle Exadata一体机时需要综合考虑成本效益、现有IT环境兼容性、未来的可扩展性和维护支持等因素。Exadata作为一款高...
2、抽象工厂+反射+配置文件实现数据库无缝切换 3、序列化/反序列化+泛型集合的应用 4、利用ASP.net HttpHandler实现防盗链 5、网站安全性方面:ASP.net防SQL注入及Web Service Soap头加密技术 6、ASP.net母板页 7、...
### 企业战略管理知识点解析 #### 一、企业战略单元角色理解 - **金牛类经营单位**(选项C)通常产生大量的现金余额,能够支持其他需要现金的经营单位。这类经营单位通常处于成熟期,市场竞争格局稳定,企业拥有较...