一、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 */ protected Properties defaults; Properties property
三、初始化方法
Properties提供兩種方式來創建Properties對象,第一種是不指定默認values對象的創建方法,另外一種是指定默認values對象的創建方法。但是此時是沒有加載屬性值的,加載key/value屬性必須通過專門的方法來加載。
/** * 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; } 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 * <code>null</code> 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 */ public String 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 */ public String 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 * <cite>The Java™ Language Specification</cite>. * <p> * 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 void load(InputStream inStream) throws IOException { load0(new LineReader(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. * <p> * Properties are processed in terms of lines. There are two * kinds of line, <i>natural lines</i> and <i>logical lines</i>. * A natural line is defined as a line of * characters that is terminated either by a set of line terminator * characters (<code>\n</code> or <code>\r</code> or <code>\r\n</code>) * 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 * <code>\</code>. 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. * * <p> * A natural line that contains only white space characters is * considered blank and is ignored. A comment line has an ASCII * <code>'#'</code> or <code>'!'</code> 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 * (<code>' '</code>, <code>'\u0020'</code>), tab * (<code>'\t'</code>, <code>'\u0009'</code>), and form feed * (<code>'\f'</code>, <code>'\u000C'</code>) to be white * space. * * <p> * 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 <i>not</i> 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 2<i>n</i> contiguous backslashes * before a line terminator (or elsewhere) encodes <i>n</i> * backslashes after escape processing. * * <p> * 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 <code>'='</code>, * <code>':'</code>, 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,<p> * * <code>\:\=</code><p> * * would be the two-character key <code>":="</code>. Line * terminator characters can be included using <code>\r</code> and * <code>\n</code> escape sequences. Any white space after the * key is skipped; if the first non-white space character after * the key is <code>'='</code> or <code>':'</code>, 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 * <code>""</code>. Once the raw character sequences * constituting the key and element are identified, escape * processing is performed as described above. * * <p> * As an example, each of the following three lines specifies the key * <code>"Truth"</code> and the associated element value * <code>"Beauty"</code>: * <p> * <pre> * Truth = Beauty * Truth:Beauty * Truth :Beauty * </pre> * As another example, the following three lines specify a single * property: * <p> * <pre> * fruits apple, banana, pear, \ * cantaloupe, watermelon, \ * kiwi, mango * </pre> * The key is <code>"fruits"</code> and the associated element is: * <p> * <pre>"apple, banana, pear, cantaloupe, watermelon, kiwi, mango"</pre> * Note that a space appears before each <code>\</code> so that a space * will appear after each comma in the final result; the <code>\</code>, * line terminator, and leading white space on the continuation line are * merely discarded and are <i>not</i> replaced by one or more other * characters. * <p> * As a third example, the line: * <p> * <pre>cheeses * </pre> * specifies that the key is <code>"cheeses"</code> and the associated * element is the empty string <code>""</code>.<p> * <p> * * <a name="unicodeescapes"></a> * 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 * <cite>The Java™ Language Specification</cite>). * * The differences from the character escape sequences and Unicode * escapes used for characters and strings are: * * <ul> * <li> Octal escapes are not recognized. * * <li> The character sequence <code>\b</code> does <i>not</i> * represent a backspace character. * * <li> The method does not treat a backslash character, * <code>\</code>, before a non-valid escape character as an * error; the backslash is silently dropped. For example, in a * Java string the sequence <code>"\z"</code> would cause a * compile time error. In contrast, this method silently drops * the backslash. Therefore, this method treats the two character * sequence <code>"\b"</code> as equivalent to the single * character <code>'b'</code>. * * <li> 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. * * <li> Only a single 'u' character is allowed in a Uniocde escape * sequence. * * </ul> * <p> * 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 void load(Reader reader) throws IOException { load0(new LineReader(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. * * <p>The XML document must have the following DOCTYPE declaration: * <pre> * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> * </pre> * Furthermore, the document must satisfy the properties DTD described * above. * * <p>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 <tt>IOException</tt>. * @throws InvalidPropertiesFormatException Data on input stream does not * constitute a valid XML document with the mandated document type. * @throws NullPointerException if <code>in</code> is null. * @see #storeToXML(OutputStream, String, String) * @since 1.5 */ public synchronized void loadFromXML(InputStream in) throws IOException, InvalidPropertiesFormatException { if (in == null) throw new NullPointerException(); 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 * <code>Properties</code> table to the output character stream in a * format suitable for using the {@link #load(java.io.Reader) load(Reader)} * method. * <p> * Properties from the defaults table of this <code>Properties</code> * table (if any) are <i>not</i> written out by this method. * <p> * If the comments argument is not null, then an ASCII <code>#</code> * character, the comments string, and a line separator are first written * to the output stream. Thus, the <code>comments</code> 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 <code>Writer</code> * and if the next character in comments is not character <code>#</code> or * character <code>!</code> then an ASCII <code>#</code> is written out * after that line separator. * <p> * Next, a comment line is always written, consisting of an ASCII * <code>#</code> character, the current date and time (as if produced * by the <code>toString</code> method of <code>Date</code> for the * current time), and a line separator as generated by the <code>Writer</code>. * <p> * Then every entry in this <code>Properties</code> table is * written out, one per line. For each entry the key string is * written, then an ASCII <code>=</code>, then the associated * element string. For the key, all space characters are * written with a preceding <code>\</code> character. For the * element, leading space characters, but not embedded or trailing * space characters, are written with a preceding <code>\</code> * character. The key and element characters <code>#</code>, * <code>!</code>, <code>=</code>, and <code>:</code> are written * with a preceding backslash to ensure that they are properly loaded. * <p> * After the entries have been written, the output stream is flushed. * The output stream remains open after this method returns. * <p> * * @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 <tt>IOException</tt>. * @exception ClassCastException if this <code>Properties</code> object * contains any keys or values that are not <code>Strings</code>. * @exception NullPointerException if <code>writer</code> is null. * @since 1.6 */ public void store(Writer writer, String comments) throws IOException { store0((writer instanceof BufferedWriter)?(BufferedWriter)writer : new BufferedWriter(writer), comments, false); } /** * Writes this property list (key and element pairs) in this * <code>Properties</code> table to the output stream in a format suitable * for loading into a <code>Properties</code> table using the * {@link #load(InputStream) load(InputStream)} method. * <p> * Properties from the defaults table of this <code>Properties</code> * table (if any) are <i>not</i> written out by this method. * <p> * 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: * <ul> * <li>The stream is written using the ISO 8859-1 character encoding. * * <li>Characters not in Latin-1 in the comments are written as * <code>\u</code><i>xxxx</i> for their appropriate unicode * hexadecimal value <i>xxxx</i>. * * <li>Characters less than <code>\u0020</code> and characters greater * than <code>\u007E</code> in property keys or values are written * as <code>\u</code><i>xxxx</i> for the appropriate hexadecimal * value <i>xxxx</i>. * </ul> * <p> * After the entries have been written, the output stream is flushed. * The output stream remains open after this method returns. * <p> * @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 <tt>IOException</tt>. * @exception ClassCastException if this <code>Properties</code> object * contains any keys or values that are not <code>Strings</code>. * @exception NullPointerException if <code>out</code> 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. * * <p>The XML document will have the following DOCTYPE declaration: * <pre> * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> * </pre> * *<p>If the specified comment is <code>null</code> then no comment * will be stored in the document. * * <p>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 <code>null</code> * if no comment is desired. * @param encoding the name of a supported * <a href="../lang/package-summary.html#charenc"> * character encoding</a> * * @throws IOException if writing to the specified output stream * results in an <tt>IOException</tt>. * @throws NullPointerException if <code>os</code> is <code>null</code>, * or if <code>encoding</code> is <code>null</code>. * @throws ClassCastException if this <code>Properties</code> object * contains any keys or values that are not * <code>Strings</code>. * @see #loadFromXML(InputStream) * @since 1.5 */ public void storeToXML(OutputStream os, String comment, String encoding) throws IOException { if (os == null) throw new NullPointerException(); XMLUtils.save(this, os, comment, encoding); } storeToXML(...)
四、源碼分析
主要針對加載屬性方法(load/loadFromXML)和寫出屬性到磁盤文件方法來進行分析(store/storeToXML)。
1、load(Reader)和load(InputStream)
這兩個方法是指定從文本文件中加載key/value屬性值,底層都是將流封裝成為LineReader對象,然后通過load0方法來加載屬性鍵值對的,加載完屬性后流對象是不會關閉的。這兩個方法對應的properties文件格式如下:
# this is comment key1:value1 key2=value2 key3 : vlaue3 key4 : value4 # the value is 'value4 ', because the Properties only trim the space of the split charset before and after. # key5 = value5 # this is error, the key not start with the space. key6 value7 Properties Text File
LineReader源碼分析:
class LineReader { /** * 根據字節流創建LineReader對象 * * @param inStream * 屬性鍵值對對應的字節流對象 */ public LineReader(InputStream inStream) { this.inStream = inStream; inByteBuf = new byte[8192]; } /** * 根據字符流創建LineReader對象 * * @param reader * 屬性鍵值對對應的字符流對象 */ public LineReader(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 */ int readLine() 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; } return len; } } // 判斷是根據字符流還是字節流讀取當前字符 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) { return len; } } // 查看是否是轉義字符 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 { return len; } } } } }
根據這個源碼,我們可以看出一些特征:readLine這個方法每次讀取一行數據;如果我們想在多行寫數據,那么可以使用'\'來進行轉義,在該轉義符號后面換行,是被允許的。
load0方法源碼:
private void load0(LineReader lr) throws IOException { char[] convtBuf = new char[1024]; // 讀取的字符總數 int limit; // 當前key所在位置 int keyLen; // value的起始位置 int valueStart; // 當前字符 char c; // 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 < limit) { // 獲取當前字符 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 < limit) { // 獲取當前字符 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格式如下所示:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> <comment>comments</comment> <entry key="key7">value7</entry> <entry key="key6">value7</entry> <entry key="key4">value4 </entry> <entry key="key3">vlaue3</entry> <entry key="key2">value2</entry> <entry key="key1">value1</entry> </properties> Properties XML File
底層調用的是XMLUtil.load方法,在該方法中是使用DOM方式來訪問xml文件的,在這里不做詳細的介紹。
3、store(InputStream/Reader,String)方法
該方法主要是將屬性值寫出到文本文件中,並寫出一個comment的注釋。底層調用的是store0方法。針對store(InputStream,String)方法,我們可以看到在調用store0方法的時候,進行字節流封裝成字符流,並且指定字符集為8859-1。源碼如下:
private void store0(BufferedWriter bw, String comments, boolean escUnicode) throws IOException { if (comments != null) { // 寫出注釋, 如果是中文注釋,那么轉化成為8859-1的字符 writeComments(bw, comments); } // 寫出時間注釋 bw.write("#" + new Date().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類。<br/> * jdk1.7文檔地址:http://docs.oracle.com/javase/7/docs/api/<br/> * java.util.Properties繼承自HashTable,最主要的子類是Provider * * @author jsliuming * */ public class PropertiesApp { public static void main(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 = new Properties(); 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<String> 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