commons-configuration2:properties文件写入中文(no escape)
来源:互联网 发布:手机网页源码怎样测试 编辑:程序博客网 时间:2024/05/22 14:33
properties 是java标准支持的配置文件格式,默认编码ISO 8859-1
,unicode字符会被转义(Unicode escapes)
参见 https://docs.oracle.com/javase/6/docs/api/java/util/Properties.html?is-external=true
所以在使用commons-configuration2
写properties文件时,即使你将编码设置为UTF-8
,写入properties文件的中文也会被转义。就像下面这段代码:
PropertiesConfiguration config = ... config.setProperty("database.jdbc.username", "中文测试"); // 创建OutputStreamWriter实例,指定编码为"UTF-8" OutputStreamWriter wirter = new OutputStreamWriter( new FileOutputStream(new File("d:\\tmp\\test.properties")), "UTF-8"); config.write(wirter); wirter.close();
生成的test.properties文件内容如下
database.jdbc.username = \u4E2D\u6587\u6D4B\u8BD5
不完美
如果只考虑properties配置被程序读写的情况,这并不是问题。
但在工程应用中,有的时候我们需要在应用环境手工编辑properties配置,这种情况下就尴尬了,根本看不懂啊。
所以我不需要commons-configuration2
写properties文件时对uncode字符转义.
为了解决这个问题,花时间研究了commons-configuration2
的代码,搞清楚了状况:
properties文件的写操作是由org.apache.commons.configuration2.PropertiesConfiguration.PropertiesWriter
类实现的。
具体是由下面这个PropertiesWriter
类中的 ValueTransformer
接口实例实现的(不得不说apache旗下的开源项目质量很高,文档注释真是很完备,变量方法命名规范,看注释就够清晰了)
/** * A translator for escaping property values. This translator performs a * subset of transformations done by the ESCAPE_JAVA translator from Commons * Lang 3. */ // escape 转义实现 private static final CharSequenceTranslator ESCAPE_PROPERTIES = new AggregateTranslator( new LookupTranslator(new String[][] { { "\\", "\\\\" } }), new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE()), UnicodeEscaper.outsideOf(32, 0x7f)); /** * A {@code ValueTransformer} implementation used to escape property values. * This implementation applies the transformation defined by the * {@link #ESCAPE_PROPERTIES} translator. */ private static final ValueTransformer TRANSFORMER = new ValueTransformer() { @Override public Object transformValue(Object value) { // value转String String strVal = String.valueOf(value); // 调用ESCAPE_PROPERTIES完成escape return ESCAPE_PROPERTIES.translate(strVal); } };
找到了问题原因就好办了,因为properties文件对unicode字符转义是java默认标准,所以这个类没有什么开关可以禁止escape,
但看上面这个transformValue方法中,第一步先将value转为String,第二步将String转义,如果省掉这第二步,直接返回String不就满足要求了么?
MyPropertiesWriter
所以解决办法就是自己定义一个PropertiesWriter
子类,重写调用TRANSFORMER 常量的writeProperty(String key, Object value, boolean forceSingleLine)
方法(TRANSFORMER常量只被writeProperty方法使用)。
在writeProperty
方法中调用自己写的ValueTransformer就可以了。
下面是代码实现
MyPropertiesWriter.java
package net.gdface.facelog.service;import java.io.IOException;import java.io.Writer;import java.util.List;import org.apache.commons.configuration2.PropertiesConfiguration.PropertiesWriter;import org.apache.commons.configuration2.convert.ListDelimiterHandler;import org.apache.commons.configuration2.convert.ValueTransformer;/** * 实现properties文件中unicode字符不转义(escape)直接输出 * @author guyadong * */public class MyPropertiesWriter extends PropertiesWriter { // 自定义实现的ValueTransformer,直接返回String,没有escape过程 private final ValueTransformer TRANSFORMER = new ValueTransformer(){ @Override public Object transformValue(Object value) { // return String.valueOf(value); }}; public MyPropertiesWriter(Writer writer, ListDelimiterHandler delHandler) { super(writer, delHandler); } /** * 代码从父类方法中原样复制没有改变,主要是为调用自定义的TRANSFORMER */ @Override public void writeProperty(String key, Object value, boolean forceSingleLine) throws IOException { String v; if (value instanceof List) { v = null; List<?> values = (List<?>) value; if (forceSingleLine) { try { v = String.valueOf(getDelimiterHandler() .escapeList(values, TRANSFORMER)); } catch (UnsupportedOperationException uoex) { // the handler may not support escaping lists, // then the list is written in multiple lines } } if (v == null) { writeProperty(key, values); return; } } else { v = String.valueOf(getDelimiterHandler().escape(value, TRANSFORMER)); } write(escapeKey(key)); write(fetchSeparator(key, value)); write(v); writeln(null); }}
MyIOFactory
有了自定义的MyPropertiesWriter
如何让PropertiesConfiguration
使用它呢?
进一步研究代码,可以知道PropertiesConfiguration
是通过 IOFactory
接口来获取PropertiesWriter
实例的。
参见PropertiesConfiguration.setIOFactory(IOFactory ioFactory)
方法。 commons-configuration2
提供的IOFactory
默认实现DefaultIOFactory
类提供的就是PropertiesWriter
实例。
所以我们可以自实现一个返回MyPropertiesWriter
实例的IOFactory
通过上面setIOFactory
方法提供给PropertiesConfiguration
就可以了。
下面是IOFactory
实现代码
MyIOFactory.java
package net.gdface.facelog.service;import java.io.Writer;import org.apache.commons.configuration2.PropertiesConfiguration.DefaultIOFactory;import org.apache.commons.configuration2.PropertiesConfiguration.PropertiesWriter;import org.apache.commons.configuration2.convert.ListDelimiterHandler;public class MyIOFactory extends DefaultIOFactory { @Override public PropertiesWriter createPropertiesWriter(Writer out, ListDelimiterHandler handler) { // 返回 MyPropertiesWriter实例 return new MyPropertiesWriter(out, handler); }}
最后一步
再回到本文最开始的那段代码,只需要增一行setIOFactory
方法调用代码就大功告成:
PropertiesConfiguration config = ... // 指定使用自定义的MyPropertiesWriter实例来完成文件写操作 config.setIOFactory(new MyIOFactory()); config.setProperty("database.jdbc.username", "中文测试"); // 创建OutputStreamWriter实例,指定编码为"UTF-8" OutputStreamWriter wirter = new OutputStreamWriter( new FileOutputStream(new File("d:\\tmp\\test.properties")), "UTF-8"); config.write(wirter); wirter.close();
不用想结果肯定是正确的
database.jdbc.username = 中文测试
- commons-configuration2:properties文件写入中文(no escape)
- java:学习commons-configuration2读取配置文件xml,properties
- 使用commons-configuration2实现xml文件读取为对象
- properties属性文件中无法写入中文?
- 【JAVA】properties文件不能写入中文或者写入中文乱码问题
- 读取、写入properties文件
- Properties(读取、删除、写入properties文件)
- apache-comnons系列之commons-configuration2 学习笔记
- 读取中文Properties文件
- Eclipse中properties文件读取时中文乱码、指定更新、写入中文变unicode码的解决方法
- java 读取和写入properties文件
- Java向Properties文件中写入内容
- 【Java编程】写入、读取、遍历Properties文件
- 【Java编程】写入、读取、遍历Properties文件
- Java向Properties文件中写入内容
- 【Java编程】写入、读取、遍历Properties文件
- Properties文件的读取与写入
- springboot maven filter写入properties文件
- Java 深入学习(7) —— Object.hashCode()的返回值与对象内存地址的关系
- 日本IT资讯-2017/11/22-软银【AI威胁的并非体力劳动者,而是脑力劳动者】
- (二十五)基础系列 数据库
- Mac OS 批量删除短信
- 以前学习JAVA时接触到的基础知识(一)
- commons-configuration2:properties文件写入中文(no escape)
- 替换空格
- JS基础学习(十)
- office怎么也卸载不干净,解决办法
- Qt5.6.0 移植到ARM(tq2440)步骤及问题记录
- codeforces C. Marco and GCD Sequence
- LeetCode 461. Hamming Distance
- 网易云课堂\『李兴华java培训23』MongoDB数据库\章节2课时20游标.sql
- 关于c语言中的运算符及注意事项