1. 概述
大多数Java应用程序需要在某些时候使用属性,通常我们是在编译代码之外将参数存储为键值对。
在Java SE API里有对属性的支持 。java.util.Properties是为处理此类配置文件而设计的实用程序类。这就是我们将在本文中关注的内容。
2.加载属性
2.1 从属性文件加载
让我们从一个用于从属性文件加载键值对开始。
加载在类路径上可用的两个文件:
app.properties:
version=1.0
name=TestApp
date=2019-07-02
catalog:
c1=files
c2=images
c3=videos
虽然建议属性文件使用*.properties*后缀,但这并不是必需的。
我们可以很简单地将属性加载到Properties实例中:
@Test
public void test_loadProperties() throws IOException {
String rootPath = "src/test/resources/";
String appConfigPath = rootPath + "app.properties";
String catalogConfigPath = rootPath + "catalog";
Properties appProps = new Properties();
appProps.load(new FileInputStream(appConfigPath));
Properties catalogProps = new Properties();
catalogProps.load(new FileInputStream(catalogConfigPath));
String appVersion = appProps.getProperty("version");
assertEquals("1.0", appVersion);
assertEquals("files", catalogProps.getProperty("c1"));
}
只要文件的内容符合属性文件格式要求,就可以通过Properties类正确解析。
这里是属性文件格式的更多详细信息。
2.2. 从XML文件加载
除了属性文件,Properties类还可以加载符合特定DTD规范的XML文件。
以下是从XML文件加载键值对的示例
icons.xml:
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>xml example</comment>
<entry key="fileIcon">icon1.jpg</entry>
<entry key="imageIcon">icon2.jpg</entry>
<entry key="videoIcon">icon3.jpg</entry>
</properties>
现在,让我们加载它:
@Test
public void test_loadXML() throws IOException {
String rootPath = "src/test/resources/";
String iconConfigPath = rootPath + "icons.xml";
Properties iconProps = new Properties();
iconProps.loadFromXML(new FileInputStream(iconConfigPath));
assertEquals("icon1.jpg", iconProps.getProperty("fileIcon"));
}
3.获取属性
我们可以使用*getProperty(String key)和getProperty(String key,String defaultValue)*来获取其键的值。
如果键值对存在,则两个方法都将返回相应的值。但是如果没有这样的键值对,前者将返回null,而后者将返回defaultValue。
测试代码:
@Test
public void test_getProperty() throws IOException {
String rootPath = "src/test/resources/";
String appConfigPath = rootPath + "app.properties";
Properties appProps = new Properties();
appProps.load(new FileInputStream(appConfigPath));
String appVersion = appProps.getProperty("version");
String appName = appProps.getProperty("name", "defaultName");
String appGroup = appProps.getProperty("group", "defaultGroup");
String appDownloadAddr = appProps.getProperty("downloadAddr");
assertEquals("1.0", appVersion);
assertEquals("TestApp", appName);
assertEquals("defaultGroup", appGroup);
assertNull(appDownloadAddr);
}
需要注意的是:Properties类从Hashtable类继承了*get()*方法,但不建议您使用它来获取值。
因为它的get()方法将返回一个Object值,该值只能转换为String,
而getProperty()方法已经为我们将原始Object值转换为String了。
下面的代码将抛出异常:
float appVerFloat = (float) appProps.get("version");
4.设置属性
我们可以使用*setProperty()*方法更新现有的键值对或添加新的键值对。
测试代码:
@Test
public void test_setProperty() throws IOException {
String rootPath = "src/test/resources/";
String appConfigPath = rootPath + "app.properties";
Properties appProps = new Properties();
appProps.load(new FileInputStream(appConfigPath));
appProps.setProperty("name", "NewAppName");
appProps.setProperty("downloadAddr", "xxxx");
String newAppName = appProps.getProperty("name");
assertEquals("NewAppName", newAppName);
String newAppDownloadAddr = appProps.getProperty("downloadAddr");
assertEquals("xxxx", newAppDownloadAddr);
appProps.put("version", 2);
String version = appProps.getProperty("version");
assertNull(version);
}
虽然Properties类从Hashtable类继承了*put()方法和putAll()*方法,但还是不建议使用它们, 原因和get()方法相同。
下面的代码将无法正常工作,当使用getProperty()获取其值时,它将返回null:
appProps.put("version", 2);
5.删除属性
如果要删除键值对,可以使用*remove()*方法。
测试代码:
@Test
public void test_remove() throws IOException {
String rootPath = "src/test/resources/";
String appConfigPath = rootPath + "app.properties";
Properties appProps = new Properties();
appProps.load(new FileInputStream(appConfigPath));
String versionBeforeRemoval = appProps.getProperty("version");
assertEquals("1.0", versionBeforeRemoval);
appProps.remove("version");
String versionAfterRemoval = appProps.getProperty("version");
assertNull(versionAfterRemoval);
}
6.存储
6.1. 存储到属性文件
Properties类提供了一个*store()*方法来输出键值对。
测试代码:
@Test
public void test_storeProperties() throws IOException {
String rootPath = "src/test/resources/";
String newAppConfigPropertiesFile = rootPath + "newApp.properties";
Properties appProps = new Properties();
appProps.setProperty("name", "NewAppName");
appProps.setProperty("download", "downloadUrl");
appProps.store(new FileWriter(newAppConfigPropertiesFile), "store to properties file");
Properties newAppProps = new Properties();
newAppProps.load(new FileInputStream(newAppConfigPropertiesFile));
String newAppName = newAppProps.getProperty("name");
assertEquals("NewAppName", newAppName);
String newAppDownload = newAppProps.getProperty("download");
assertEquals("downloadUrl", newAppDownload);
}
生成的文件内容如下
#store to properties file
#Tue Jul 02 22:28:18 JST 2019
download=downloadUrl
name=NewAppName
第二个参数用于添加注释的。如果您不想写任何注释,只需使用null即可。
6.2. 存储到XML文件
Properties类还提供*storeToXML()*方法,以XML格式输出键值对。
@Test
public void test_storeXML() throws IOException {
String rootPath = "src/test/resources/";
String newAppConfigXmlFile = rootPath + "newApp.xml";
Properties appProps = new Properties();
appProps.setProperty("name", "NewAppName");
appProps.setProperty("download", "downloadUrl");
appProps.storeToXML(new FileOutputStream(newAppConfigXmlFile), "store to xml file");
Properties newAppProps = new Properties();
newAppProps.loadFromXML(new FileInputStream(newAppConfigXmlFile));
String newAppName = newAppProps.getProperty("name");
assertEquals("NewAppName", newAppName);
String newAppDownload = newAppProps.getProperty("download");
assertEquals("downloadUrl", newAppDownload);
}
生成的文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>store to xml file</comment>
<entry key="download">downloadUrl</entry>
<entry key="name">NewAppName</entry>
</properties>
第二个参数与*store()*方法中的参数相同。
7.其他方法
Properties类还提供了一些其他方法来操作属性。
示例代码:
@Test
public void test_otherMethod() throws IOException {
String rootPath = "src/test/resources/";
String newAppConfigPropertiesFile = rootPath + "newApp.properties";
Properties appProps = new Properties();
appProps.load(new FileInputStream(newAppConfigPropertiesFile));
appProps.list(System.out);
Enumeration<Object> valueEnumeration = appProps.elements();
while (valueEnumeration.hasMoreElements()) {
System.out.println(valueEnumeration.nextElement());
}
Enumeration<Object> keyEnumeration = appProps.keys();
while (keyEnumeration.hasMoreElements()) {
System.out.println(keyEnumeration.nextElement());
}
int size = appProps.size();
assertEquals(2, size);
}
输出如下:
download=downloadUrl
name=NewAppName
downloadUrl
NewAppName
download
name
8.默认属性列表
一个属性对象可以包含另一个属性对象作为其默认的属性列表。 如果在原始属性键中找不到属性键,则将搜索默认属性列表。
除了“ app.properties ”之外, 我们在类路径上还有另一个文件“ default.properties ”:
default.properties:
site=www.google.com
name=DefaultAppName
topic=Properties
category=core-java
测试代码
@Test
public void test_defaultPropertiesObject() throws IOException {
String rootPath = "src/test/resources/";
String defaultConfigPath = rootPath + "default.properties";
Properties defaultProps = new Properties();
defaultProps.load(new FileInputStream(defaultConfigPath));
String appConfigPath = rootPath + "app.properties";
// 设置默认的属性列表
Properties appProps = new Properties(defaultProps);
appProps.load(new FileInputStream(appConfigPath));
String appVersion = appProps.getProperty("version");
assertEquals("1.0", appVersion);
String appName = appProps.getProperty("name");
assertEquals("TestApp", appName);
String defaultSite = appProps.getProperty("site");
assertEquals("www.google.com", defaultSite);
}
9.结论
在本文中,我们讨论了基本的Properties类用法,包括:
- 如何在Properties和XML格式中使用Properties加载和存储键值对
- 如何在Properties对象中操作键值对,例如检索值,更新值,获取其大小
- 如何使用Properties对象的默认列表
最后,往常一样,代码可以在Github上找到。