properties使用

什麼是Properties?

Properties(Java.util.Properties),該類主要用於讀取Java的配置檔案,不同的程式語言有自己所支援的配置檔案,配置檔案中很多變數是經常改變的,為了方便使用者的配置,能讓使用者夠脫離程式本身去修改相關的變數設定。就像在Java中,其配置檔案常為.properties檔案,是以鍵值對的形式進行引數配置的。

Properties 詳解

properties結構

Api介紹

  • 建構函式

建構函式 說明
Properties() 建立空的Properties
Properties(Properties ps) 基於已經存在的properties去建立
  • 常用方法

方法 說明
public synchronized void load(InputStream inStream) 給予輸入流去載入Properties
public synchronized void load(Reader reader) 給予文字輸入流去載入Properties
Object setProperty(String key, String value) 設定屬性
public synchronized void load(InputStream inStream) 給予輸入流去載入Properties
public void store(Writer writer, String comments) 儲存檔案
public String getProperty(String key) 獲取properties key
  • 原始碼講解

load原始碼分析

指定從流中載入key/value屬性值,底層都是將流封裝成為LineReader物件,然後通過load0方法來載入屬性鍵值對的,載入完屬性後流物件是不會關閉的。這兩個方法對應的properties檔案格式如下:

 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;
                    }
                }

            }
        }
    }

store原始碼分析

private void store0(BufferedWriter bw, String comments, boolean escUnicode) throws IOException {
 2         if (comments != null) {
 3             // 寫出註釋, 如果是中文註釋,那麼轉化成為8859-1的字元
 4             writeComments(bw, comments);
 5         }
 6         // 寫出時間註釋
 7         bw.write("#" + new Date().toString());
 8         // 新起一行
 9         bw.newLine();
10         // 進行執行緒間同步的併發控制
11         synchronized (this) {
12             for (Enumeration e = keys(); e.hasMoreElements();) {
13                 String key = (String) e.nextElement();
14                 String val = (String) get(key);
15                 // 針對空格進行轉義,並根據是否需要進行8859-1編碼
16                 key = saveConvert(key, true, escUnicode);
17                 /*
18                  * No need to escape embedded and trailing spaces for value,
19                  * hence pass false to flag.
20                  */
21                 // value不對空格進行轉義
22                 val = saveConvert(val, false, escUnicode);
23                 // 寫出key/value鍵值對
24                 bw.write(key + "=" + val);
25                 bw.newLine();
26             }
27         }
28         bw.flush();
29     }

properties實戰

實現讀取ex1.properties檔案寫入另外一個檔案ex2.properties

  • 準備檔案test.properties
#bbaba
#Mon Jun 07 11:38:21 CST 2021
hah=ceshi
  • 開始拷貝
Properties properties = new Properties();
properties.load(new FileReader(new File("test.properties")));
System.out.println(properties.get("hah"));
properties.store(new FileWriter(new File("test2.properties")),"ceshi2");
  • 控制檯輸出
ceshi
Process finished with exit code 0

此時classpath下可以檢視到新建的test2.properties檔案。

結束

識別下方二維碼!回覆: 入群 ,掃碼加入我們交流群!

點贊是認可,在看是支援