摘要:本文章分为五个篇章结合java Api文档非常全面的讲解了Properties,作为个人的学习笔记觉得很有意义。第一篇来自于
www.ibm.com/developerworks/java/library/j-tiger02254.html,做出了简单的拮取与翻译,其他篇章均来自于对代码的chew。
作者: Aivin Ray
篇章一:Loading Properties from XML
XML 属性文档具有以下 DOCTYPE 声明: <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> 注意,导入或导出属性时不 访问系统 URI (http://java.sun.com/dtd/properties.dtd);该系统 URI 仅作为一个惟一标识 DTD 的字符串:
<?xml version="1.0" encoding="UTF-8"?>
<!-- DTD for properties -->
<!ELEMENT properties ( comment?, entry* ) >
<!ATTLIST properties version CDATA #FIXED "1.0">
<!ELEMENT comment (#PCDATA) > //注释
<!ELEMENT entry (#PCDATA) > //值
<!ATTLIST entry key CDATA #REQUIRED> //key
<!-- DTD for properties -->
<!ELEMENT properties ( comment?, entry* ) >
<!ATTLIST properties version CDATA #FIXED "1.0">
<!ELEMENT comment (#PCDATA) > //注释
<!ELEMENT entry (#PCDATA) > //值
<!ATTLIST entry key CDATA #REQUIRED> //key
下面给出一个实例:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>Hi</comment>
<entry key="foo">bar</entry>
<entry key="fu">baz</entry>
</properties>
下面运用loadFromXML(InputStream is)读取xml:

















下面运用storeToXML(OutputStream os, String comment)方法来创建xml:




















输出打印的结果为:











为什么会选择把properties和xml关联起来?
J2SE1.5以前的版本要求直接使用XML解析器来装载配置文件并存储设置。虽然这并非是一件困难的事情,并且解析器是平台的标准部分,但是额外的工作总是有点让人烦。最近更新的java.util.Properties类现在提供了一种为程序装载和存储设置的更容易的方法:loadFromXML(InputStream is)和storeToXML(OutputStream os, String comment)方法。使用 XML 文件还是使用老式的 a=b 类型的文件完全取决于您自己。老式文件从内存的角度看肯定是轻量级的。不过,由于 XML 的普遍使用,人们会期望 XML 格式流行起来,因为它已经被广泛使用了,只不过没有用到 Properties 对象。
不过在我看来properties同xml一样,引用API中的一句话:“它将资源包中大部分(如果不是全部)特定于语言环境的信息隔离开来。”,让我们可以轻松的进行修改及动态载入。
篇章二:更好理解它的方法
在开始这一篇章的讲解之前,我们先提一下两个类:
FileInputStream类:一个文件字节输入流,从中可以读出一个字节或一批字节
FileOutputStream类:一个文件字节输出流,可向流中写一个字节或一批字节
第一个方法:public void load(InputStream inStream) throws IOException从输入流中读取属性列表(键和元素对)。
第二个方法:public void store(OutputStream out,String comments)throws IOException将load方法读取到的属性列表写入out流中。这里的comments是注释
下面我们用代码来说明:
这里我们已经创建了两个properties文件:
文件1:
#test.properties
1=a
2=b
3=c
文件二:
#temp.test.properties
today=Monday
tomorrow=Tuesday
下面我们将就Store方法进行讨论











public static void main(String args[]){
propertiesdemo demo=new propertiesdemo();
demo.init();
}

private void init() ...{

try ...{
InputStream fis = new FileInputStream("G:/Sunny/Keta/JTest/src/com/build/test.properties");
//从输入流中读取属性列表(键和元素对)
prop.load(fis);
//调用 Hashtable 的方法 put。使用 getProperty 方法提供并行性。
//强制要求为属性的键和值使用字符串。返回值是 Hashtable 调用 put 的结果。
OutputStream fos = new FileOutputStream("G:/Sunny/Keta/JTest/src/com/build/temp.properties");
prop.setProperty("2","w");
//prop.setProperty("3","sorry");
//以适合使用 load 方法加载到 Properties 表中的格式, 将此Properties 表中的属性列表(键和元素对)写入输出流
prop.store(fos, "Update '" + 2 + "' value ");

}catch (IOException e) ...{
e.printStackTrace();
System.err.println("Visit " + 2 + " for updating " + "w" + " value error");
}

}
}
























演示代码的结果是test.properties中的内容不变
而temp.properties中的内容如下:
#Update '2' value
#Sun Dec 02 00:16:31 CST 2007
3=c
2=w
1=a
3=c
2=w
1=a
我们可以发现当我们得到test.properties的属性列表后并调用setProperty对属性列表做出修改后得到的新的属性列表覆盖了temp.properties的内容。输入顺序正如api文档所述:如果 comments 变量非 null,则首先将 ASCII
#
字符、注释字符串和一个行分隔符写入输出流。因此,该
comments
可用作一个标识注释。接下来总是写入一个注释行,该行包括一个 ASCII
#
字符、当前的日期和时间(就好像使用
Date
的
toString
方法获取当前时间一样)和一个由 Writer 生成的行分隔符。然后将此
Properties
表中的所有项写入 out,一次一行。
如果只想在temp.properties的后面添加而不希望覆盖 ,我们只需这样写new FileOutputStream(String name,true)即可。
下面我们将写一个读properties的模块:






篇章3:如何解决中文乱码的问题
如果你的properties文件中含有中文,在不做任何处理的情况下你得到的将是一连串的问号。在那一步中产生了这一问题呢?在API中我们可以在
load方法中阅读这一段:假定该流使用 ISO 8859-1 字符编码;也就是每个字节是一个 Latin1 字符。对于非 Latin1 的字符和某些特殊字符,可以使用与字符和字符串字面值所用的类似转义序列。
也就是说我们要把汉字转换为/uXXXX。
如何做到这一点,我这里有两个办法:
办法一:使用native2ascii 命令(具体用法csdn上可以搜到很多)。
办法二:重写native2ascii命令
对于办法二,我重写了一个模块,基本实现native2ascii的转义功能:


















































在写这个模块之前我使用的是这个模块当然这个模块经常被用来处理jsp的中文字符问题
代码如下:
















































































篇章4:读取Properties文件三种方法
1。使用java.util.Properties类的load()方法
示例:InputStream in=new BufferedInputStream(new FileInputStream(name));
或者 InputStream in=JProperties.class.getResourceAsStream(name);
或者 InputStream in=JProperties.class.getClassLoader().getResourceAsStream(name);
或者 InputStreamin=ClassLoader.getSystemResourceAsStream(name);
然后:
Properties p=new Properties();
p.load(in);
示例:InputStream in=new BufferedInputStream(new FileInputStream(name));
或者 InputStream in=JProperties.class.getResourceAsStream(name);
或者 InputStream in=JProperties.class.getClassLoader().getResourceAsStream(name);
或者 InputStreamin=ClassLoader.getSystemResourceAsStream(name);
然后:
Properties p=new Properties();
p.load(in);
2。使用java.util.ResourceBundle类的getBundle()方法
示例:ResourceBundlerb=ResourceBundle.getBundle(name,Locale.getDefault());
示例:ResourceBundlerb=ResourceBundle.getBundle(name,Locale.getDefault());
3。使用java.util.PropertyResourceBundle类的构造函数
示例:InputStream in=new BufferedInputStream(new FileInputStream(name));
ResourceBundler b=new PropertyResourceBundle(in);
示例:InputStream in=new BufferedInputStream(new FileInputStream(name));
ResourceBundler b=new PropertyResourceBundle(in);
补充:
Servlet中可以使用javax.servlet.ServletContext的getResourceAsStream()方法
示例:InputStreamin=context.getResourceAsStream(path);
Properties p=new Properties();
p.load(in);
Servlet中可以使用javax.servlet.ServletContext的getResourceAsStream()方法
示例:InputStreamin=context.getResourceAsStream(path);
Properties p=new Properties();
p.load(in);
篇章五:最后的模块——对properites值的修改















































































































这段代码是极其有意义的,它非常全面的提供了Properties的修改操作,同时删除了重复的键值。