java.util.Properties 的使用
- 方法简介
- 代码示例
- Properties()、Properties(Properties defaults)
- load(Reader reader)、load(InputStream inStream)
- setProperty(String key, String value)
- getProperty(String key)、getProperty(String key, String defaultValue)
- propertyNames()、stringPropertyNames()
- store(Writer writer, String comments)、store(OutputStream out, String comments)
- list(PrintStream out)、list(PrintWriter out)
- loadFromXML(InputStream in)
- storeToXML(OutputStream os, String comment)、storeToXML(OutputStream os, String comment, String encoding)
方法简介
方法 | 简介 | |
---|---|---|
1 | Properties() | 新建一个空的 Properties 对象 |
2 | Properties(Properties defaults) | 新建一个带有默认值的 Properties 对象 |
3 | load(Reader reader) | 从字符流中加载属性列表 |
4 | load(InputStream inStream) | 从字节流中加载属性列表 |
5 | setProperty(String key, String value) | 设置属性值 |
6 | getProperty(String key) | 获取属性值,若属性列表、默认属性列表都不存在,则返回 null |
7 | getProperty(String key, String defaultValue) | 获取属性值,若属性列表、默认属性列表都不存在,则返回参数 defaultValue |
8 | propertyNames() | 获取所有属性名的Enumeration<?> ,包括主属性列表和默认属性列表中的,若碰到非 String 的键将抛出异常 |
9 | stringPropertyNames() | 获取所有属性名,返回值为Set<String> ,且会忽略非 String 的键 |
10 | store(Writer writer, String comments) | 将属性列表写入字符流中,以适合 load(Reader) 方法加载的格式,默认的属性不会被写出 |
11 | store(OutputStream out, String comments) | 将属性列表写入字节流中,以适合 load(InputStream) 方法加载的格式,默认的属性不会被写出 |
12 | list(PrintStream out) | 将此属性列表打印到指定的输出流。这个方法对于调试很有用。 |
13 | list(PrintWriter out) | 将此属性列表打印到指定的输出流。这个方法对于调试很有用。 |
14 | loadFromXML(InputStream in) | 从 XML 中加载属性列表 |
15 | storeToXML(OutputStream os, String comment) | 将属性列表写入指定流 |
16 | storeToXML(OutputStream os, String comment, String encoding) | 将属性列表写入指定流 |
代码示例
Properties()、Properties(Properties defaults)
Properties()、Properties(Properties defaults)
都是创建一个Properties
对象,区别在于后者包含一个默认的属性列表,会将其赋值给defaults
属性。
// Properties 继承了 Hashtable
public class Properties extends Hashtable<Object,Object> {
/**
* A property list that contains default values for any keys not
* found in this property list.
*
* @serial
*/
protected Properties defaults;
/**
* Creates an empty property list with no default values.
*/
public Properties() {
this(null);
}
/**
* Creates an empty property list with the specified defaults.
*
* @param defaults the defaults.
*/
public Properties(Properties defaults) {
this.defaults = defaults;
}
}
public static void constructor() {
Properties prop = new Properties();
Properties propWithDefault = new Properties(defaults());
System.out.println("id: " + prop.getProperty("id"));
System.out.println("id: " + propWithDefault.getProperty("id"));
}
public static Properties defaults() {
Properties properties = new Properties();
properties.setProperty("id", "100");
return properties;
}
如果在主属性列表中找不到对应键的话,会到默认属性列表defaults
中去寻找。
id: null
id: 100
load(Reader reader)、load(InputStream inStream)
load(Reader reader)、load(InputStream inStream)
都是从流中加载属性列表,基本可以说是以行为单位。并且有以下的规则
- 以 #、! 开头的行会被认为是注释,并被忽略
- 空白行会被忽略
- 可以用 = 或 : 分隔键值对
- 键、值前后的空白字符将被忽略
- 此方法返回后指定的流仍然保持打开的状态
- 具体的规则、例子可以查看
load(Reader reader)
方法的注释
load(Reader reader)
是子字符流为基础的,可以直接处理中文;load(InputStream inStream)
是以字节流为基础的,且使用 ISO 8859-1 编码进行处理,会造成中文乱码。另外要注意 properties 文件的编码要是 utf-8。需要手动关闭指定的流。
# aa=aaa
! bb =bbb
Truth1 = Beauty
Truth2:Beauty
Truth3 :Beauty
Truits apple, banana, pear, \
cantaloupe, watermelon, \
kiwi, mango
cheeses
name=小明
age\=18
father\:tom
public static void load() throws IOException {
Properties prop = new Properties();
// 使用这行代码时,小明会乱码
// prop.load(Test1.class.getResourceAsStream("/test.properties"));
prop.load(new InputStreamReader(Test1.class.getResourceAsStream("/test.properties"), "UTF-8"));
prop.forEach((k, v)-> System.out.println(k + "=" + v));
}
可以看出注释被忽略了;空行被忽略了;键和值前后的空白字符都被忽略了;cheeses 的值为空字符串;中文没有乱码;7~9行这种形式的被解析成了一个键值对;\=
、\:
被转义成了普通字符,成为了键的一部分。
Truth2=Beauty
Truth3=Beauty
cheeses=
father:tom=
age=18=
name=小明
Truits=apple, banana, pear, cantaloupe, watermelon, kiwi, mango
Truth1=Beauty
setProperty(String key, String value)
设置属性,并返回指定键的上一个值,即旧的值。
public static void setProperty() {
Properties prop = new Properties();
Object old1 = prop.setProperty("id", "100");
Object old2 = prop.setProperty("id", "200");
System.out.println("old1: " + old1);
System.out.println("old2: " + old2);
System.out.println("id: " + prop.get("id"));
}
old1: null
old2: 100
id: 200
getProperty(String key)、getProperty(String key, String defaultValue)
两个方法都是获取指定键对应的属性值,都会先从主属性列表中查找,若没有找到的话,再查找默认属性列表defaults
,找到则直接返回,若没有找到,getProperty(String key)
会返回 null,getProperty(String key, String defaultValue)
会返回参数 defaultValue。若找到的属性值不是 String 类型,也按照以上的规则。
public static void getProperty() {
Properties prop = new Properties();
String id = prop.getProperty("id");
String idWithDefault = prop.getProperty("id", "NO123");
System.out.println("id: " + id);
System.out.println("idWithDefault: " + idWithDefault);
}
id: null
idWithDefault: NO123
propertyNames()、stringPropertyNames()
两个方法都用于返回属性列表中的所有键,不同的是propertyNames()
返回值是Enumeration<?>
,stringPropertyNames()
返回值是Set<String>
;当遇到非 String 的键时,propertyNames()
抛出异常ClassCastException
,stringPropertyNames()
忽略非 String 的键。
public static void propertyNames() {
Properties prop = new Properties(defaults());
prop.setProperty("name", "tom");
prop.setProperty("age", "18");
// 放入一个非 String 的键
// prop.put(new Object(), "");
System.out.println("--stringPropertyNames--");
Set<String> keys = prop.stringPropertyNames();
keys.forEach(System.out::println);
System.out.println("--propertyNames--");
Enumeration<?> enumeration = prop.propertyNames();
while (enumeration.hasMoreElements()) {
Object o = enumeration.nextElement();
System.out.println(o);
}
}
public static Properties defaults() {
Properties properties = new Properties();
properties.setProperty("id", "100");
return properties;
}
当属性列表中不存在非 String 的键时
--stringPropertyNames--
age
name
id
--propertyNames--
age
name
id
当属性列表中存在非 String 的键时
--stringPropertyNames--
age
name
id
--propertyNames--
Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String
at java.util.Properties.enumerate(Properties.java:1097)
at java.util.Properties.propertyNames(Properties.java:1008)
at com.example.heima.properties.Test1.propertyNames(Test1.java:76)
at com.example.heima.properties.Test1.main(Test1.java:15)
store(Writer writer, String comments)、store(OutputStream out, String comments)
将属性列表写入字符流、字节流中,以适合 load(Reader) 方法加载的格式,默认的属性不会被写出。写入之后,将 flush 输出流。此方法返回后,输出流保持打开状态。
public static void store() throws IOException {
Properties prop = new Properties(defaults());
prop.setProperty("name", "小明");
prop.setProperty("age", "18");
prop.store(new FileWriter("E:\\test1.properties"), "测试 store");
prop.store(new FileOutputStream("E:\\test2.properties"), "测试 store");
Properties prop1 = new Properties();
prop1.load(new FileInputStream("E:\\test2.properties"));
Properties prop2 = new Properties();
prop2.load(new FileReader("E:\\test2.properties"));
prop1.list(System.out);
prop2.list(System.out);
}
public static Properties defaults() {
Properties properties = new Properties();
properties.setProperty("id", "100");
return properties;
}
输出
-- listing properties --
age=18
name=小明
-- listing properties --
age=18
name=小明
文件内容如下,默认的属性列表没有没写入文件,比如 id;注释中的中文被编码了;使用store(OutputStream out, String comments)
时会将中文的键值对进行编码。
test1.properties
#\u6D4B\u8BD5 store
#Sat Dec 26 15:56:12 CST 2020
age=18
name=小明
test2.properties
#\u6D4B\u8BD5 store
#Sat Dec 26 15:56:12 CST 2020
age=18
name=\u5C0F\u660E
list(PrintStream out)、list(PrintWriter out)
将此属性列表打印到指定的输出流。这个方法对于调试很有用。遇到非 String 的键时会抛出异常ClassCastException
。
public static void list() throws IOException {
Properties prop = new Properties(defaults());
prop.setProperty("name", "小明");
prop.setProperty("age", "18");
prop.list(System.out);
prop.put(new Object(), "");
prop.list(System.out);
}
-- listing properties --
age=18
name=小明
id=100
-- listing properties --
Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String
at java.util.Properties.enumerate(Properties.java:1097)
at java.util.Properties.list(Properties.java:1047)
at com.example.heima.properties.Test1.list(Test1.java:110)
at com.example.heima.properties.Test1.main(Test1.java:16)
loadFromXML(InputStream in)
从 XML 中加载属性列表,xml 必须有以下声明<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
,且 xml 必须满足上面 DTD。方法返回之后指定的流将被关闭。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>测试 loadFromXML</comment>
<entry key="username">小明</entry>
<entry key="email">123@qq.com</entry>
</properties>
public static void loadFromXML() throws IOException {
Properties prop = new Properties();
prop.loadFromXML(Test1.class.getResourceAsStream("/test.xml"));
prop.list(System.out);
}
-- listing properties --
email=123@qq.com
username=小明
storeToXML(OutputStream os, String comment)、storeToXML(OutputStream os, String comment, String encoding)
以 xml 文件的格式将属性列表写入指定的流中,不包含默认属性列表。storeToXML(os, comment)
与storeToXML(os, comment, "UTF-8")
的行为是相同的。在此方法返回后,指定的流保持打开状态。
public static void storeToXML() throws IOException {
Properties prop = new Properties(defaults());
prop.setProperty("name", "小明");
prop.setProperty("age", "18");
prop.storeToXML(new FileOutputStream("E:\\test1.xml"), "测试 storeToXML");
Properties prop1 = new Properties();
prop1.loadFromXML(new FileInputStream("E:\\test1.xml"));
prop1.list(System.out);
}
public static Properties defaults() {
Properties properties = new Properties();
properties.setProperty("id", "100");
return properties;
}
age=18
name=小明
写出的 xml 文件内容
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>测试 storeToXML</comment>
<entry key="age">18</entry>
<entry key="name">小明</entry>
</properties>