一、Properties类介绍
java.util.Properties继承自java.util.Hashtable,从jdk1.1版本开始,Properties的实现基本上就没有什么大的变动。从http://docs.oracle.com/javase/7/docs/api/的jdk7的官方api文档中我们可以看到对Properties类的介绍。Properties class是一个持久化的属性保存对象,可以将属性内容写出到stream中或者从stream中读取属性内容,在底层的Hashtable中,每一对属性的key和value都是按照string类型来保存的。 Properties可以将其他的Properties对象作为默认的值,Properties继承自Hashtable,所以Hashtable的所有方法Properties对象均可以访问。
Properties支持文本方式和xml方式的数据存储。在文本方式中,格式为key:value,其中分隔符可以是:冒号(:)、等号(=)、空格。其中空格可以作为key的结束,同时获取的值回将分割符号两端的空格去掉。
Properties只支持1对1模式的属性设置,而且不支持多层多级属性设置。
二、Properties类属性
protected Properties defaults:包含默认values的Properties对象,默认为null。我们在找不到对应key的情况下,就回递归的从这个默认列表中里面来找。
/**
* A property list that contains default values for any keys not
* found in this property list.
*
* @serial*/
protectedProperties defaults;
Properties property
三、初始化方法
Properties提供两种方式来创建Properties对象,第一种是不指定默认values对象的创建方法,另外一种是指定默认values对象的创建方法。但是此时是没有加载属性值的,加载key/value属性必须通过专门的方法来加载。
/**
* Creates an empty property list with no default values.*/
publicProperties() {this(null);
}/**
* Creates an empty property list with the specified defaults.
*
* @param defaults the defaults.*/
publicProperties(Properties defaults) {this.defaults =defaults;
}
Properties Construction Method
四、常用方法
getProperty(String):根据指定的key获取对应的属性value值,如果在自身的存储集合中没有找到对应的key,那么就直接到默认的defaults属性指定的Properties中获取属性值。
/**
* Searches for the property with the specified key in this property list.
* If the key is not found in this property list, the default property list,
* and its defaults, recursively, are then checked. The method returns
* null
if the property is not found.
*
* @param key the property key.
* @return the value in this property list with the specified key value.
* @see #setProperty
* @see #defaults*/
publicString getProperty(String key) {
Object oval= super.get(key);
String sval= (oval instanceof String) ? (String)oval : null;return ((sval == null) && (defaults != null)) ?defaults.getProperty(key) : sval;
}
getProperty(String)
getProperty(String, String):当getProperty(String)方法返回值为null的时候,返回给定的默认值,而不是返回null。
/**
* Searches for the property with the specified key in this property list.
* If the key is not found in this property list, the default property list,
* and its defaults, recursively, are then checked. The method returns the
* default value argument if the property is not found.
*
* @param key the hashtable key.
* @param defaultValue a default value.
*
* @return the value in this property list with the specified key value.
* @see #setProperty
* @see #defaults*/
publicString getProperty(String key, String defaultValue) {
String val=getProperty(key);return (val == null) ?defaultValue : val;
}
getProperty(String,String)
load(InputStream):从byte stream中加载key/value键值对,要求所有的key/value键值对是按行存储,同时是用ISO-8859-1编译的。
/**
* Reads a property list (key and element pairs) from the input
* byte stream. The input stream is in a simple line-oriented
* format as specified in
* {@link #load(java.io.Reader) load(Reader)} and is assumed to use
* the ISO 8859-1 character encoding; that is each byte is one Latin1
* character. Characters not in Latin1, and certain special characters,
* are represented in keys and elements using Unicode escapes as defined in
* section 3.3 of
* The Java™ Language Specification.
*
* The specified stream remains open after this method returns.
*
* @param inStream the input stream.
* @exception IOException if an error occurred when reading from the
* input stream.
* @throws IllegalArgumentException if the input stream contains a
* malformed Unicode escape sequence.
* @since 1.2*/
public synchronized voidload(InputStream inStream) throws IOException {
load0(newLineReader(inStream));
}
load(InputStream)
load(Reader):从字符流中加载key/value键值对,要求所有的键值对都是按照行来存储的。
/**
* Reads a property list (key and element pairs) from the input
* character stream in a simple line-oriented format.
*
* Properties are processed in terms of lines. There are two
* kinds of line, natural lines and logical lines.
* A natural line is defined as a line of
* characters that is terminated either by a set of line terminator
* characters (\n
or \r
or \r\n
)
* or by the end of the stream. A natural line may be either a blank line,
* a comment line, or hold all or some of a key-element pair. A logical
* line holds all the data of a key-element pair, which may be spread
* out across several adjacent natural lines by escaping
* the line terminator sequence with a backslash character
* \
. Note that a comment line cannot be extended
* in this manner; every natural line that is a comment must have
* its own comment indicator, as described below. Lines are read from
* input until the end of the stream is reached.
*
*
* A natural line that contains only white space characters is
* considered blank and is ignored. A comment line has an ASCII
* '#'
or '!'
as its first non-white
* space character; comment lines are also ignored and do not
* encode key-element information. In addition to line
* terminators, this format considers the characters space
* (' '
, '\u0020'
), tab
* ('\t'
, '\u0009'
), and form feed
* ('\f'
, '\u000C'
) to be white
* space.
*
*
* If a logical line is spread across several natural lines, the
* backslash escaping the line terminator sequence, the line
* terminator sequence, and any white space at the start of the
* following line have no affect on the key or element values.
* The remainder of the discussion of key and element parsing
* (when loading) will assume all the characters constituting
* the key and element appear on a single natural line after
* line continuation characters have been removed. Note that
* it is not sufficient to only examine the character
* preceding a line terminator sequence to decide if the line
* terminator is escaped; there must be an odd number of
* contiguous backslashes for the line terminator to be escaped.
* Since the input is processed from left to right, a
* non-zero even number of 2n contiguous backslashes
* before a line terminator (or elsewhere) encodes n
* backslashes after escape processing.
*
*
* The key contains all of the characters in the line starting
* with the first non-white space character and up to, but not
* including, the first unescaped '='
,
* ':'
, or white space character other than a line
* terminator. All of these key termination characters may be
* included in the key by escaping them with a preceding backslash
* character; for example,
*
* \:\=
*
* would be the two-character key ":="
. Line
* terminator characters can be included using \r
and
* \n
escape sequences. Any white space after the
* key is skipped; if the first non-white space character after
* the key is '='
or ':'
, then it is
* ignored and any white space characters after it are also
* skipped. All remaining characters on the line become part of
* the associated element string; if there are no remaining
* characters, the element is the empty string
* ""
. Once the raw character sequences
* constituting the key and element are identified, escape
* processing is performed as described above.
*
*
* As an example, each of the following three lines specifies the key
* "Truth"
and the associated element value
* "Beauty"
:
*
*
* Truth = Beauty
* Truth:Beauty
* Truth :Beauty
*
* As another example, the following three lines specify a single
* property:
*
*
* fruits apple, banana, pear, \
* cantaloupe, watermelon, \
* kiwi, mango
*
* The key is "fruits"
and the associated element is:
*
*
"apple, banana, pear, cantaloupe, watermelon, kiwi, mango"
* Note that a space appears before each \
so that a space
* will appear after each comma in the final result; the \
,
* line terminator, and leading white space on the continuation line are
* merely discarded and are not replaced by one or more other
* characters.
*
* As a third example, the line:
*
*
cheeses
*
* specifies that the key is "cheeses"
and the associated
* element is the empty string ""
.
*
*
* Characters in keys and elements can be represented in escape
* sequences similar to those used for character and string literals
* (see sections 3.3 and 3.10.6 of
* The Java™ Language Specification).
*
* The differences from the character escape sequences and Unicode
* escapes used for characters and strings are:
*
*
*
Octal escapes are not recognized.*
*
The character sequence\b
does
not
* represent a backspace character.
*
*
The method does not treat a backslash character,* \
, before a non-valid escape character as an
* error; the backslash is silently dropped. For example, in a
* Java string the sequence "\z"
would cause a
* compile time error. In contrast, this method silently drops
* the backslash. Therefore, this method treats the two character
* sequence "\b"
as equivalent to the single
* character 'b'
.
*
*
Escapes are not necessary for single and double quotes;* however, by the rule above, single and double quote characters
* preceded by a backslash still yield single and double quote
* characters, respectively.
*
*
Only a single 'u' character is allowed in a Uniocde escape* sequence.
*
*
*
* The specified stream remains open after this method returns.
*
* @param reader the input character stream.
* @throws IOException if an error occurred when reading from the
* input stream.
* @throws IllegalArgumentException if a malformed Unicode escape
* appears in the input.
* @since 1.6*/
public synchronized voidload(Reader reader) throws IOException {
load0(newLineReader(reader));
}
load(Reader)
loadFromXML(InputStream):从xml文件中加载property,底层使用XMLUtils.load(Properties,InputStream)方法来加载。
/**
* Loads all of the properties represented by the XML document on the
* specified input stream into this properties table.
*
*
The XML document must have the following DOCTYPE declaration:
*
* <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
*
* Furthermore, the document must satisfy the properties DTD described
* above.
*
*
The specified stream is closed after this method returns.
*
* @param in the input stream from which to read the XML document.
* @throws IOException if reading from the specified input stream
* results in an IOException.
* @throws InvalidPropertiesFormatException Data on input stream does not
* constitute a valid XML document with the mandated document type.
* @throws NullPointerException if in
is null.
* @see #storeToXML(OutputStream, String, String)
* @since 1.5*/
public synchronized void loadFromXML(InputStream in)
throws IOException, InvalidPropertiesFormatException
{if (in == null)throw newNullPointerException();
XMLUtils.load(this, in);in.close();
}
loadFromXML(InputStream)
store(OutputStream/Writer,comments)将所有的property(保存defaults的)都写出到流中,同时如果给定comments的话,那么要加一个注释。
/**
* Writes this property list (key and element pairs) in this
* Properties
table to the output character stream in a
* format suitable for using the {@link #load(java.io.Reader) load(Reader)}
* method.
*
* Properties from the defaults table of this Properties
* table (if any) are not written out by this method.
*
* If the comments argument is not null, then an ASCII #
* character, the comments string, and a line separator are first written
* to the output stream. Thus, the comments
can serve as an
* identifying comment. Any one of a line feed ('\n'), a carriage
* return ('\r'), or a carriage return followed immediately by a line feed
* in comments is replaced by a line separator generated by the Writer
* and if the next character in comments is not character #
or
* character !
then an ASCII #
is written out
* after that line separator.
*
* Next, a comment line is always written, consisting of an ASCII
* #
character, the current date and time (as if produced
* by the toString
method of Date
for the
* current time), and a line separator as generated by the Writer
.
*
* Then every entry in this Properties
table is
* written out, one per line. For each entry the key string is
* written, then an ASCII =
, then the associated
* element string. For the key, all space characters are
* written with a preceding \
character. For the
* element, leading space characters, but not embedded or trailing
* space characters, are written with a preceding \
* character. The key and element characters #
,
* !
, =
, and :
are written
* with a preceding backslash to ensure that they are properly loaded.
*
* After the entries have been written, the output stream is flushed.
* The output stream remains open after this method returns.
*
*
* @param writer an output character stream writer.
* @param comments a description of the property list.
* @exception IOException if writing this property list to the specified
* output stream throws an IOException.
* @exception ClassCastException if this Properties
object
* contains any keys or values that are not Strings
.
* @exception NullPointerException if writer
is null.
* @since 1.6*/
public voidstore(Writer writer, String comments)
throws IOException
{
store0((writer instanceof BufferedWriter)?(BufferedWriter)writer
:newBufferedWriter(writer),
comments,false);
}/**
* Writes this property list (key and element pairs) in this
* Properties
table to the output stream in a format suitable
* for loading into a Properties
table using the
* {@link #load(InputStream) load(InputStream)} method.
*
* Properties from the defaults table of this Properties
* table (if any) are not written out by this method.
*
* This method outputs the comments, properties keys and values in
* the same format as specified in
* {@link #store(java.io.Writer, java.lang.String) store(Writer)},
* with the following differences:
*
*
The stream is written using the ISO 8859-1 character encoding.*
*
Characters not in Latin-1 in the comments are written as* \u
xxxx for their appropriate unicode
* hexadecimal value xxxx.
*
*
Characters less than\u0020
and characters greater
* than \u007E
in property keys or values are written
* as \u
xxxx for the appropriate hexadecimal
* value xxxx.
*
*
* After the entries have been written, the output stream is flushed.
* The output stream remains open after this method returns.
*
* @param out an output stream.
* @param comments a description of the property list.
* @exception IOException if writing this property list to the specified
* output stream throws an IOException.
* @exception ClassCastException if this Properties
object
* contains any keys or values that are not Strings
.
* @exception NullPointerException if out
is null.
* @since 1.2*/
public void store(OutputStream out, String comments)
throws IOException
{
store0(new BufferedWriter(new OutputStreamWriter(out, "8859_1")),
comments,true);
}
store(...)
storeToXML(OutputSteam, comment, encoding):写出到xml文件中。
/**
* Emits an XML document representing all of the properties contained
* in this table, using the specified encoding.
*
*
The XML document will have the following DOCTYPE declaration:
*
* <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
*
*
*
If the specified comment is null
then no comment
* will be stored in the document.
*
*
The specified stream remains open after this method returns.
*
* @param os the output stream on which to emit the XML document.
* @param comment a description of the property list, or null
* if no comment is desired.
* @param encoding the name of a supported
* character encoding
*
* @throws IOException if writing to the specified output stream
* results in an IOException.
* @throws NullPointerException if os
is null
,
* or if encoding
is null
.
* @throws ClassCastException if this Properties
object
* contains any keys or values that are not
* Strings
.
* @see #loadFromXML(InputStream)
* @since 1.5*/
public voidstoreToXML(OutputStream os, String comment, String encoding)
throws IOException
{if (os == null)throw newNullPointerException();
XMLUtils.save(this, os, comment, encoding);
}
storeToXML(...)
四、源码分析
主要针对加载属性方法(load/loadFromXML)和写出属性到磁盘文件方法来进行分析(store/storeToXML)。
1、load(Reader)和load(InputStream)
这两个方法是指定从文本文件中加载key/value属性值,底层都是将流封装成为LineReader对象,然后通过load0方法来加载属性键值对的,加载完属性后流对象是不会关闭的。这两个方法对应的properties文件格式如下:
# this iscomment
key1:value1
key2=value2
key3 : vlaue3
key4 : value4
# the valueis 'value4', because the Properties only trim the space of the split charset before and after.
# key5=value5
#this iserror, the key not start with the space.
key6 value7
Properties Text File
LineReader源码分析:
classLineReader {/**
* 根据字节流创建LineReader对象
*
* @param inStream
* 属性键值对对应的字节流对象*/
publicLineReader(InputStream inStream) {this.inStream =inStream;
inByteBuf= new byte[8192];
}/**
* 根据字符流创建LineReader对象
*
* @param reader
* 属性键值对对应的字符流对象*/
publicLineReader(Reader reader) {this.reader =reader;
inCharBuf= new char[8192];
}//字节流缓冲区, 大小为8192个字节
byte[] inByteBuf;//字符流缓冲区,大小为8192个字符
char[] inCharBuf;//当前行信息的缓冲区,大小为1024个字符
char[] lineBuf = new char[1024];//读取一行数据时候的实际读取大小
int inLimit = 0;//读取的时候指向当前字符位置
int inOff = 0;//字节流对象
InputStream inStream;//字符流对象
Reader reader;/**
* 读取一行,将行信息保存到{@link lineBuf}对象中,并返回实际的字符个数
*
* @return 实际读取的字符个数
* @throws IOException*/
intreadLine() throws IOException {//总的字符长度
int len = 0;//当前字符
char c = 0;
boolean skipWhiteSpace= true;
boolean isCommentLine= false;
boolean isNewLine= true;
boolean appendedLineBegin= false;
boolean precedingBackslash= false;
boolean skipLF= false;while (true) {if (inOff >=inLimit) {//读取一行数据,并返回这一行的实际读取大小
inLimit = (inStream == null) ?reader.read(inCharBuf) : inStream.read(inByteBuf);
inOff= 0;//如果没有读取到数据,那么就直接结束读取操作
if (inLimit <= 0) {//如果当前长度为0或者是改行是注释,那么就返回-1。否则返回len的值。
if (len == 0 ||isCommentLine) {return -1;
}returnlen;
}
}//判断是根据字符流还是字节流读取当前字符
if (inStream != null) {//The line below is equivalent to calling a ISO8859-1 decoder.//字节流是根据ISO8859-1进行编码的,所以在这里进行解码操作。
c = (char) (0xff & inByteBuf[inOff++]);
}else{
c= inCharBuf[inOff++];
}//如果前一个字符是换行符号,那么判断当前字符是否也是换行符号
if(skipLF) {
skipLF= false;if (c == '\n') {continue;
}
}//如果前一个字符是空格,那么判断当前字符是不是空格类字符
if(skipWhiteSpace) {if (c == ' ' || c == '\t' || c == '\f') {continue;
}if (!appendedLineBegin && (c == '\r' || c == '\n')) {continue;
}
skipWhiteSpace= false;
appendedLineBegin= false;
}//如果当前新的一行,那么进入该if判断中
if(isNewLine) {
isNewLine= false;//如果当前字符是#或者是!,那么表示该行是一个注释行
if (c == '#' || c == '!') {
isCommentLine= true;continue;
}
}//根据当前字符是不是换行符号进行判断操作
if (c != '\n' && c != '\r') {//当前字符不是换行符号
lineBuf[len++] = c;//将当前字符写入到行信息缓冲区中,并将len自增加1.//如果len的长度大于行信息缓冲区的大小,那么对lineBuf进行扩容,扩容大小为原来的两倍,最大为Integer.MAX_VALUE
if (len ==lineBuf.length) {int newLength = lineBuf.length * 2;if (newLength < 0) {
newLength=Integer.MAX_VALUE;
}char[] buf = new char[newLength];
System.arraycopy(lineBuf,0, buf, 0, lineBuf.length);
lineBuf=buf;
}//是否是转义字符//flip the preceding backslash flag
if (c == '\\') {
precedingBackslash= !precedingBackslash;
}else{
precedingBackslash= false;
}
}else{//reached EOL
if (isCommentLine || len == 0) {//如果这一行是注释行,或者是当前长度为0,那么进行clean操作。
isCommentLine = false;
isNewLine= true;
skipWhiteSpace= true;
len= 0;continue;
}//如果已经没有数据了,就重新读取
if (inOff >=inLimit) {
inLimit= (inStream == null) ?reader.read(inCharBuf) : inStream.read(inByteBuf);
inOff= 0;if (inLimit <= 0) {returnlen;
}
}//查看是否是转义字符
if(precedingBackslash) {//如果是,那么表示是另起一行,进行属性的定义,len要自减少1.
len -= 1;//skip the leading whitespace characters in following line
skipWhiteSpace = true;
appendedLineBegin= true;
precedingBackslash= false;if (c == '\r') {
skipLF= true;
}
}else{returnlen;
}
}
}
}
}
根据这个源码,我们可以看出一些特征:readLine这个方法每次读取一行数据;如果我们想在多行写数据,那么可以使用'\'来进行转义,在该转义符号后面换行,是被允许的。
load0方法源码:
private voidload0(LineReader lr) throws IOException {char[] convtBuf = new char[1024];//读取的字符总数
intlimit;//当前key所在位置
intkeyLen;//value的起始位置
intvalueStart;//当前字符
charc;//
boolean hasSep;//是否是转义字符
boolean precedingBackslash;while ((limit = lr.readLine()) >= 0) {
c= 0;//key的长度
keyLen = 0;//value的起始位置默认为limit
valueStart =limit;//
hasSep = false;
precedingBackslash= false;//如果key的长度小于总的字符长度,那么就进入循环
while (keyLen
c =lr.lineBuf[keyLen];//如果当前字符是=或者是:,而且前一个字符不是转义字符,那么就表示key的描述已经结束
if ((c == '=' || c == ':') && !precedingBackslash) {//指定value的起始位置为当前keyLen的下一个位置
valueStart = keyLen + 1;//并且指定,去除空格
hasSep = true;break;
}else if ((c == ' ' || c == '\t' || c == '\f') && !precedingBackslash) {//如果当前字符是空格类字符,而且前一个字符不是转义字符,那么表示key的描述已经结束//指定value的起始位置为当前位置的下一个位置
valueStart = keyLen + 1;break;
}//如果当前字符为'\',那么跟新是否是转义号。
if (c == '\\') {
precedingBackslash= !precedingBackslash;
}else{
precedingBackslash= false;
}
keyLen++;
}//如果value的起始位置小于总的字符长度,那么就进入该循环
while (valueStart
c =lr.lineBuf[valueStart];//判断当前字符是否是空格类字符,达到去空格的效果
if (c != ' ' && c != '\t' && c != '\f') {//当前字符不是空格类字符,而且当前字符为=或者是:,并在此之前没有出现过=或者:字符。//那么value的起始位置继续往后移动。
if (!hasSep && (c == '=' || c == ':')) {
hasSep= true;
}else{//当前字符不是=或者:,或者在此之前出现过=或者:字符。那么结束循环。
break;
}
}
valueStart++;
}//读取key
String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);//读取value
String value = loadConvert(lr.lineBuf, valueStart, limit -valueStart, convtBuf);//包括key/value
put(key, value);
}
}
我们可以看到,在这个过程中,会将分割符号两边的空格去掉,并且分割符号可以是=,:,空格等。而且=和:的级别比空格分隔符高,即当这两个都存在的情况下,是按照=/:分割的。可以看到在最后会调用一个loadConvert方法,该方法主要是做key/value的读取,并将十六进制的字符进行转换。
2、loadFromXML方法
该方法主要是提供一个从XML文件中读取key/value键值对的方法。底层是调用的XMLUtil的方法,加载完对象属性后,流会被显示的关闭。xml格式如下所示:
comments
value7
value7
value4
vlaue3
value2
value1
Properties XML File
底层调用的是XMLUtil.load方法,在该方法中是使用DOM方式来访问xml文件的,在这里不做详细的介绍。
3、store(InputStream/Reader,String)方法
该方法主要是将属性值写出到文本文件中,并写出一个comment的注释。底层调用的是store0方法。针对store(InputStream,String)方法,我们可以看到在调用store0方法的时候,进行字节流封装成字符流,并且指定字符集为8859-1。源码如下:
private voidstore0(BufferedWriter bw, String comments, boolean escUnicode) throws IOException {if (comments != null) {//写出注释, 如果是中文注释,那么转化成为8859-1的字符
writeComments(bw, comments);
}//写出时间注释
bw.write("#" + newDate().toString());//新起一行
bw.newLine();//进行线程间同步的并发控制
synchronized (this) {for (Enumeration e =keys(); e.hasMoreElements();) {
String key=(String) e.nextElement();
String val= (String) get(key);//针对空格进行转义,并根据是否需要进行8859-1编码
key = saveConvert(key, true, escUnicode);/** No need to escape embedded and trailing spaces for value,
* hence pass false to flag.*/
//value不对空格进行转义
val = saveConvert(val, false, escUnicode);//写出key/value键值对
bw.write(key + "=" +val);
bw.newLine();
}
}
bw.flush();
}
4、storeToXML方法
将属性写出到xml文件中,底层调用的是XMLUtil.store方法。不做详细的介绍。
五、实例
直接代码:
package com.gerry.bd.properties.jdk;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;
import java.util.Set;/**
* 操作jdk自身操作属性配置文件的Properties类。
* jdk1.7文档地址:http://docs.oracle.com/javase/7/docs/api/
* java.util.Properties继承自HashTable,最主要的子类是Provider
*
* @author jsliuming
**/
public classPropertiesApp {public static voidmain(String[] args) {
InputStream input= null;//第一种,使用ClassLoad的方法获取InputStram对象。
input = PropertiesApp.class.getClassLoader().getResourceAsStream("propertiesApp.properties");//第二种,直接使用Class的方法来获取InputStream对象。必须加'/'表示在classpath路径下,如果不加的话,那么获取的是PropertiesApp这个类所在package下的文件。
input = PropertiesApp.class.getResourceAsStream("/propertiesApp.properties");
OutputStream os= null;try{
os= new FileOutputStream("storePropertiesApp.xml");
}catch(FileNotFoundException e1) {
}//第一步:创建Properties对象
Properties prop = newProperties();try{//第二步:加载属性, 不会自动关闭input输入流。
prop.load(input);//第三步:获取属性
String value1 = prop.getProperty("key1");
String value5= prop.getProperty("key5");
String value7= prop.getProperty("key7", "defaultvalue");
System.out.println("[key1:" + value1 + "],[key5:" + value5 + "],[key7:" + value7 + "]");
Set keys =prop.stringPropertyNames();
System.out.println("全部的key/value属性:");for(String key : keys) {
System.out.println("[" + key + "][" + prop.getProperty(key) + "]");
}//第四步:设置属性
prop.setProperty("key7", "value7");//第五步:保存成文件
prop.storeToXML(os, "comments");
}catch(IOException e) {
e.printStackTrace();
}finally{if(input != null) {try{
input.close();
}catch(IOException e) {//ignore
}
}if (os != null) {try{
os.close();
}catch(IOException e) {//ignore
}
}
}
}
}
PropertiesApp
结果console的输出为:
[key1:value1],[key5:null],[key7:defaultvalue]
全部的key/value属性:
[key6][value7]
[key4][value4 ]
[key3][vlaue3]
[key2][value2]
[key1][value1]
result