- 浏览: 2939 次
文章分类
最新评论
文章来自http://www.iteye.com/topic/156474
如果要对一个属性设置文件.properties文件进行操作,我们当然想到用java.util.Properties类.对于只进行属性读取, 这个类已经足够好了,但需要在Properties实例改变之后调用.store()或者.save()需要重新输出的时候,这个类就只会简单的把所有的 属性简单的输出,整个文件格式和属性的顺序都改变了,原来的注释也消失了.
附件中是一个改进过的properites文件读写类,在 java.util.Properties的基础上进行改进,在读取properties文件的时候把注释和顺序格式都记录下来,操作时候也把添加顺序记 录了,所以很好的解决了java.util.Properties类在输出的不足,同时它提供addComment()方法,可以添加注释,这样,经过处 理的properties的可读性就能继续保持下来了.
看下面的示范代码:
FileInputStream input = new FileInputStream( "e:/input.properties" );
SafeProperties safeProp = new SafeProperties();
safeProp.load(input);
input.close();
safeProp.addComment( "New Comment" );
safeProp.put( "New-Key" , "New====Value" );
FileOutputStream output = new FileOutputStream( "e:/output.properties" );
safeProp.store(output, null );
output.close();
很感谢你的这个class,我正需要这样一个类来处理我的Properties文件。
不过,我在使用的时候还是发现有一个问题,就是如果重新设置原有属性的值时后,程序不是在原来的位置修改属性,而是将原有属性删除,再作为新属性添加,这样属性的位置就发生了变动。稍微修改你的类就可以解决这个问题:
1、首先修改remove方法:
- public int remove(String key) {
- for ( int index = 0 ; index < commentOrEntrys.size(); index++) {
- Object obj = commentOrEntrys.get(index);
- if (obj instanceof PropertyEntry) {
- if (obj != null ) {
- if (key.equals(((PropertyEntry) obj).getKey())) {
- commentOrEntrys.remove(obj);
- return index;
- }
- }
- }
- }
- return commentOrEntrys.size();
- }
2、修补putOrUpdate方法:
- public void putOrUpdate(String key, String value) {
- PropertyEntry pe = new PropertyEntry(key, value);
- int index = remove(key);
- commentOrEntrys.add(index,pe);
-
}
第二篇文章:http://www.iteye.com/topic/883695
最近赋闲在家闲的蛋疼,找工作也不顺利,就安静下来学一些常用开源项目,在翻struts2的时候看到读取properties配置文件是自己定义的
reader来读取,因为之前上班的时候常常使用到properties的读写,对于jdk本身的properties在保存的时候会把注释忽略掉这点深
恶痛绝,一直想重新写一个properties文件读写的工具类,但是大致翻了一下properties的代码和文档,发现properties的规则挺
多,没有几天时间怕是难以完成就一直搁下了。这次看到struts2的代码就想拿来借鉴一下,于是就把properties的东西读了一遍,发觉很多东西
是之前忽略甚至不知道的,于是记下和兄弟们共享,如有错欢迎指正,概念颇多,容易晕头,建议找头脑清醒的时候看。
JDK Properties核心在读取配置文件的
load0方法的JDK文档总结如下,这也是后续的几个重要的概念的出处:
1.注释符为:'#'或者'!'。空白字符为:' ', '\t', '\f'。key/value分隔符为:'='或者':'。行分隔符为:'\r','\n','\r\n'。
2.自然行是使用行分隔符或者流的结尾来分割的行。逻辑行可能分割到多个自然行中,使用反斜杠'\'来连接多个自然行。
3.注释行是使用注释符作为首个非空白字符的自然行。
4.空白字符的自然行会被认为是空行而被忽略。
5.properties文件的key为从首个非空白字符开始直到(但不包括)首个非转义的'=', ':'或者非行结束符的空白字符为止。
6.key后面的第一个非空白字符如果是”=”或者”:”,那么这个字符后面所有空白字符都会被忽略掉。
7.可以使用转义序列表示key和value(当然此处的字符转义序列和unicode的转义有一些差别,jdk文档都有列出来)。
properties是一个包含了key、value对的文本文档,key,value的界定是正确读取properties的关键,那么key、 value是如何界定的呢?上面第5点是对key的不完全界定但是并未涉及到value,这些,都只有从源码当中来寻找答案。
load0源码和注解如下:
- private void load0(LineReader lr) throws IOException {
- char [] convtBuf = new char [ 1024 ];
- //行的长度
- int limit;
- //key的长度
- int keyLen;
- //value的开始点
- int valueStart;
- //当前读取的字符
- char c;
- //是否是key/value的分隔符
- boolean hasSep;
- //前一个字符是否是反斜杠
- boolean precedingBackslash;
- //把通过LineReader读取来的逻辑行进行遍历,一个个char的进行处理。
- while ((limit = lr.readLine()) >= 0 ) {
- c = 0 ;
- keyLen = 0 ;
- valueStart = limit;
- hasSep = false ;
- precedingBackslash = false ;
- //循环获取key的长度
- while (keyLen < limit) {
- c = lr.lineBuf[keyLen];
- //当字符为key/value分隔符:'='或':'并且前一个字符不是反斜杠的时候,key长度读取结束,并且把hasSep设置为true,break。
- if ((c == '=' || c == ':' ) && !precedingBackslash) {
- valueStart = keyLen + 1 ;
- hasSep = true ;
- break ;
- }
- //当字符为空白字符' '或'\t'或'\f'并且前一个字符不是反斜杠的时候,key长度读取结束,break。
- else if ((c == ' ' || c == '\t' || c == '\f' ) && !precedingBackslash) {
- valueStart = keyLen + 1 ;
- break ;
- }
- //当连续存在奇数个反斜杠的时候, precedingBackslash为true。
- if (c == '\\' ) {
- precedingBackslash = !precedingBackslash;
- } else {
- precedingBackslash = false ;
- }
- keyLen++;
- }
- //循环获取value开始的位置
- while (valueStart < limit) {
- c = lr.lineBuf[valueStart];
- //如果字符不为所有的空白字符:' ', '\t', '\f'的时候
- if (c != ' ' && c != '\t' && c != '\f' ) {
- //如果前面不是key/value的分隔符,而是空白字符,而该字符是key/value分隔符
- if (!hasSep && (c == '=' || c == ':' )) {
- hasSep = true ;
- } else {
- //结束读取
- break ;
- }
- }
- valueStart++;
- }
- //loadConvert是进行字符串转义的方法,就不用关心了。
- String key = loadConvert(lr.lineBuf, 0 , keyLen, convtBuf);
- String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);
- put(key, value);
- }
- }
通过如上的代码可以看出,key/value分割符'=', ':'与空白字符:' ', '\t', '\f'是区分key、value的关键:
key的界定为:逻辑行中,从首个非空白字符开始直到(但不包括)首个非转义的'=', ':'或者非行结束符的空白字符为止。(和前面第5点基本一致)
value的界定为:逻辑行中,非转义的key/value分隔符(此处不仅仅包括'=',':',还包括' ', '\t', '\f')后面的第一个非空白字符(非' ', '\t', '\f'字符)开始到逻辑行结束的所有字符。
另外key、value还有如下特征:
1.因为LineReader是读取的逻辑行,所以key、value中可以包含多个自然行。
2.在“循环获取key的长度”的代码中可以看到处理key/value分隔符的方式和处理空白字符的方式很相似(除了在发现处理的字符为key/value分隔符的时候会把 hasSep变量设置为true)。而这表明:
如果空白字符后续没有key/value分隔符(“=”或者“:”),那么该空白字符会被当作key/value分隔符,从分隔符后的第一个非空 白字符起到逻辑行结束所有的字符都当作是value。也就是说:“key1 value1”,读取出来之后的key和value分别为”key1”, “value1”。
如果空白字符后续有key/value分隔符(“=”或者“:”),那么该空白字符会被忽略,key/value分隔符后的第一个非空白字符起到 逻辑行结束所有的字符都当作是value。也就是说:”key1 :value1”,读取出来之后的key和value分别为”key1”和”value1”,而不是”key1”和”:value1”。
另外,在读xwork的com.opensymphony.xwork2.util.PropertiesReader类的时候发现,它的实现和 JDK的Properties实现有出入,也就是说,如果JDK的Properties是规范的话,那么xwork的properties读取类是有 bug的。测试类如下(注释掉的Assert才能通过junit):
- public class PropertiesTest {
- @Test
- public void testLoad() throws IOException {
- File f = new File(getClass().getResource( "." ).getPath(), "test.properties" );
- InputStream in = null ;
- try {
- //java properties
- in = new FileInputStream(f);
- Properties props = new Properties();
- props.load(in);
- String s1 = props.getProperty("key" );
- Assert.assertEquals("value#with" , s1);
- String s2 = props.getProperty("comments" );
- Assert.assertEquals("" , s2);
- } finally {
- if (in != null )
- try {
- in.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- try {
- //xwork properties
- in = new FileInputStream(f);
- Reader reader = new InputStreamReader(in);
- PropertiesReader pr = new PropertiesReader(reader);
- while (pr.nextProperty()) {
- String name = pr.getPropertyName();
- String val = pr.getPropertyValue();
- if ( "key" .equals(name)) {
- Assert.assertEquals("value#with" , val);
- //Assert.assertEquals("valuecomments", val);
- }
- if ( "comments" .equals(name)) {
- Assert.assertEquals("" , val);
- //Assert.assertEquals(null, val);
- }
- }
- } finally {
- if (in != null )
- try {
- in.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
test.properties的内容如下:
好了,清楚properties的使用规则了,如果我们需要自己写一个实现在保存properties的时候注释不被忽略掉,而且按照原来的行数来保存的工具类的话,就会清晰很多了。本来想把这个工具写一下,但是写代码加调试实在太费时间,等到用的时候再来写吧。
- SafeProperties.zip (3.1 KB)
- 下载次数: 33
相关推荐
详细介绍了java.util.logging.Logger的用法和结构,对如果扩展Logger起到抛砖引玉的作用!尊重劳动成果,亲下载了要给个评价!
本文通过对数据压缩算法的简要介绍,然后以详细的示例演示了利用java.util.zip包实现数据的压缩与解压,并扩展到在网络传输方面如何应用java.util.zip包现数据压缩与解压
1. java.util.concurrent - Java 并发工具包 2. 阻塞队列 BlockingQueue 3. 数组阻塞队列 ArrayBlockingQueue 4. 延迟队列 DelayQueue 5. 链阻塞队列 LinkedBlockingQueue 6. 具有优先级的阻塞队列 ...
java.util.ConcurrentModificationException 异常问题详解1
java.util.Date与java.sql.Date互转及字符串转换为日期时间格式.docx
Tomcat内存溢出的解决方法(java.util.concurrent.ExecutionException:java.lang.OutOfMemoryError),内附解决方案!
Exception in thread “main“ java.util.InputMismatchException
java.util.concurrent系列文章(1) java.util.concurrent系列文章(1) java.util.concurrent系列文章(1) java.util.concurrent系列文章(1)
详细介绍java.util.Date和java.sql.Date相互转换的多种方法总结,希望对大家有帮助
世界范围内的时区列表。由 java.util.TimeZone 类导出
java.util包
java并发工具包 java.util.concurrent中文版-带书签版
java.util.pdf
Java并发编程工具包java.util.concurrent的UML类结构图 PDF
Java解压缩文件,并以ZIP格式压缩文件,主要是使用java.util.zip 包中的类来实现解压、压缩文件功能,如果你对这个类并不太熟悉,你正好可以参考一下这个类是如何用的。
这是我在编写struts2中遇到的问题,整理出来,包括截图,希望可以帮到大家
java.util包总结,方便大家学习。请多指教。
java.util包源码,pdf版,方便打印
java API 在包java.util中有一个GregorianCalendar类,使用它可以得到一年内某个月的日历.zip