欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文帶你全面了解Java?Properties類

 更新時間:2022年09月15日 08:32:22   作者:JAVA旭陽  
Properties是JDK1.0中引入的java類,目前也在項目中大量使用,主要用來讀取外部的配置,那除了這個,你對它其他的一些api也了解嗎??你了解它是怎么實現(xiàn)的嗎??如果不清楚的話,就通過本篇文章帶你一探究竟

概述

Properties是JDK1.0中引入的java類,目前也在項目中大量使用,主要用來讀取外部的配置,那除了這個,你對它其他的一些api也了解嗎? 你了解它是怎么實現(xiàn)的嗎? 如果不清楚的話,就通過本篇文章帶你一探究竟。

介紹

java.util.Properties繼承自java.util.Hashtable,是一個持久化的屬性保存對象,可以將屬性內(nèi)容寫出到stream中或者從stream中讀取屬性內(nèi)容。 它的重要特性如下:

  • 在底層的Hashtable中,每一對屬性的key和value都是按照string類型來保存的。
  • Properties支持文本方式和xml方式的數(shù)據(jù)存儲。在文本方式中,格式為key:value,其中分隔符可以是:冒號(:)、等號(=)、空格。其中空格可以作為key的結(jié)束,同時獲取的值回將分割符號兩端的空格去掉。
  • Properties可以將其他的Properties對象作為默認的值。
  • Hashtable的所有方法Properties對象均可以訪問,但是不建議這么做,因為Hashtable可以存放其他數(shù)據(jù)類型,這樣會導(dǎo)致Properties一些方法調(diào)用報錯。
  • 在properties文件中,可以用井號"#"來作注釋。
  • 線程安全
  • key、value不可以是null

構(gòu)造方法

Properties()

創(chuàng)建一個無默認值的空屬性列表。

Properties(Properties defaults)

創(chuàng)建一個帶有指定默認值的空屬性列表。

關(guān)鍵方法

getProperty ( String key)

根據(jù)指定的key獲取對應(yīng)的屬性value值,如果在自身的存儲集合中沒有找到對應(yīng)的key,那么就直接到默認的defaults屬性指定的Properties中獲取屬性值。

getProperty(String, String)

當getProperty(String)方法返回值為null的時候,返回給定的默認值,而不是返回null。

load ( InputStream inStream)

從byte stream中加載key/value鍵值對,要求所有的key/value鍵值對是按行存儲,同時是用ISO-8859-1編譯的, 不支持中文。

load(Reader)

從字符流中加載key/value鍵值對,要求所有的鍵值對都是按照行來存儲的。

loadFromXML(InputStream)

從xml文件中加載property,底層使用XMLUtils.load(Properties,InputStream)方法來加載。

setProperty ( String key, String value)

調(diào)用 Hashtable 的方法 put 。他通過調(diào)用基類的put方法來設(shè)置 鍵 - 值對。

store ( OutputStream out, String comments)

將所有的property(保存defaults的)都寫出到流中,同時如果給定comments的話,那么要加一個注釋。

storeToXML(OutputSteam, comment, encoding)

寫出到xml文件中。

Set stringPropertyNames()

獲取所有Properties中所有的key集合

clear ()

清除所有裝載的 鍵值對。該方法在基類中提供。

使用案例

新建配置文件app.properties

## 用戶信息
user.name:旭陽
user.age=28
user.sex 男

通過idea設(shè)置它的格式為UTF-8。

驗證讀取以及中文亂碼的問題

 @Test
    public void test1() throws IOException {
        Properties properties = new Properties();
        // 使用load inputstream
        properties.load(this.getClass().getClassLoader().getResourceAsStream("app.properties"));
        // 出現(xiàn)亂碼
        System.out.println(properties);
        // 轉(zhuǎn)碼
        System.out.println(new String(properties.getProperty("user.name").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8));

        Properties properties2 = new Properties();
        // 使用load read
        BufferedReader bf = new BufferedReader(new InputStreamReader(this.getClass().getClassLoader().getResourceAsStream("app.properties"), "UTF-8"));
        properties2.load(bf);
        System.out.println(properties2);
    }

運行結(jié)果:

保存為xml格式

 @Test
    public void test2() throws IOException {
        Properties properties2 = new Properties();
        // 使用load read
        BufferedReader bf = new BufferedReader(new InputStreamReader(this.getClass().getClassLoader().getResourceAsStream("app.properties"), "UTF-8"));
        properties2.load(bf);
        System.out.println(properties2);

        // 保存到xml
        FileOutputStream fileOutputStream = new FileOutputStream("app.xml");
        properties2.storeToXML(fileOutputStream, "alvin info", "UTF-8");
    }

運行結(jié)果:

源碼解析

源碼這部分主要分析下load(Reader)和load(InputStream)這兩個最常用的方法,這兩個方法是指定從文本文件中加載key/value屬性值,底層都是將流封裝成為LineReader對象,然后通過load0方法來加載屬性鍵值對的。

public synchronized void load(InputStream inStream) throws IOException {
        load0(new LineReader(inStream));
    }

將inputStream封裝程一個LineReader,每次可以讀取一行數(shù)據(jù)。

LineReader源碼分析:

class LineReader {
        /**
         * 根據(jù)字節(jié)流創(chuàng)建LineReader對象
         * 
         * @param inStream
         *            屬性鍵值對對應(yīng)的字節(jié)流對象
         */
        public LineReader(InputStream inStream) {
            this.inStream = inStream;
            inByteBuf = new byte[8192];
        }

        /**
         * 根據(jù)字符流創(chuàng)建LineReader對象
         * 
         * @param reader
         *            屬性鍵值對對應(yīng)的字符流對象
         */
        public LineReader(Reader reader) {
            this.reader = reader;
            inCharBuf = new char[8192];
        }

        // 字節(jié)流緩沖區(qū), 大小為8192個字節(jié)
        byte[] inByteBuf;
        // 字符流緩沖區(qū),大小為8192個字符
        char[] inCharBuf;
        // 當前行信息的緩沖區(qū),大小為1024個字符
        char[] lineBuf = new char[1024];
        // 讀取一行數(shù)據(jù)時候的實際讀取大小
        int inLimit = 0;
        // 讀取的時候指向當前字符位置
        int inOff = 0;
        // 字節(jié)流對象
        InputStream inStream;
        // 字符流對象
        Reader reader;

        /**
         * 讀取一行,將行信息保存到{@link lineBuf}對象中,并返回實際的字符個數(shù)
         * 
         * @return 實際讀取的字符個數(shù)
         * @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) {
                    // 讀取一行數(shù)據(jù),并返回這一行的實際讀取大小
                    inLimit = (inStream == null) ? reader.read(inCharBuf) : inStream.read(inByteBuf);
                    inOff = 0;
                    // 如果沒有讀取到數(shù)據(jù),那么就直接結(jié)束讀取操作
                    if (inLimit <= 0) {
                        // 如果當前長度為0或者是改行是注釋,那么就返回-1。否則返回len的值。
                        if (len == 0 || isCommentLine) {
                            return -1;
                        }
                        return len;
                    }
                }

                // 判斷是根據(jù)字符流還是字節(jié)流讀取當前字符
                if (inStream != null) {
                    // The line below is equivalent to calling a ISO8859-1 decoder.
                    // 字節(jié)流是根據(jù)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;
                    }
                }

                // 根據(jù)當前字符是不是換行符號進行判斷操作
                if (c != '\n' && c != '\r') {
                    // 當前字符不是換行符號
                    lineBuf[len++] = c;// 將當前字符寫入到行信息緩沖區(qū)中,并將len自增加1.
                    // 如果len的長度大于行信息緩沖區(qū)的大小,那么對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;
                    }
                    // 是否是轉(zhuǎn)義字符
                    // 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;
                    }
                    // 如果已經(jīng)沒有數(shù)據(jù)了,就重新讀取
                    if (inOff >= inLimit) {
                        inLimit = (inStream == null) ? reader.read(inCharBuf) : inStream.read(inByteBuf);
                        inOff = 0;
                        if (inLimit <= 0) {
                            return len;
                        }
                    }
                    // 查看是否是轉(zhuǎn)義字符
                    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這個方法每次讀取一行數(shù)據(jù);如果我們想在多行寫數(shù)據(jù),那么可以使用''來進行轉(zhuǎn)義,在該轉(zhuǎn)義符號后面換行,是被允許的。

load0方法源碼如下:

private void load0(LineReader lr) throws IOException {
        char[] convtBuf = new char[1024];
        // 讀取的字符總數(shù)
        int limit;
        // 當前key所在位置
        int keyLen;
        // value的起始位置
        int valueStart;
        // 當前字符
        char c;
        // 
        boolean hasSep;
        // 是否是轉(zhuǎn)義字符
        boolean precedingBackslash;

        while ((limit = lr.readLine()) >= 0) {
            c = 0;
            // key的長度
            keyLen = 0;
            // value的起始位置默認為limit
            valueStart = limit;
            // 
            hasSep = false;
            precedingBackslash = false;

            // 如果key的長度小于總的字符長度,那么就進入循環(huán)
            while (keyLen < limit) {
                // 獲取當前字符
                c = lr.lineBuf[keyLen];
                // 如果當前字符是=或者是:,而且前一個字符不是轉(zhuǎn)義字符,那么就表示key的描述已經(jīng)結(jié)束
                if ((c == '=' || c == ':') && !precedingBackslash) {
                    // 指定value的起始位置為當前keyLen的下一個位置
                    valueStart = keyLen + 1;
                    // 并且指定,去除空格
                    hasSep = true;
                    break;
                } else if ((c == ' ' || c == '\t' || c == '\f') && !precedingBackslash) {
                    // 如果當前字符是空格類字符,而且前一個字符不是轉(zhuǎn)義字符,那么表示key的描述已經(jīng)結(jié)束
                    // 指定value的起始位置為當前位置的下一個位置
                    valueStart = keyLen + 1;
                    break;
                }
                // 如果當前字符為'',那么跟新是否是轉(zhuǎn)義號。
                if (c == '\') {
                    precedingBackslash = !precedingBackslash;
                } else {
                    precedingBackslash = false;
                }
                keyLen++;
            }

            // 如果value的起始位置小于總的字符長度,那么就進入該循環(huán)
            while (valueStart < limit) {
                // 獲取當前字符
                c = lr.lineBuf[valueStart];
                // 判斷當前字符是否是空格類字符,達到去空格的效果
                if (c != ' ' && c != '\t' && c != '\f') {
                    // 當前字符不是空格類字符,而且當前字符為=或者是:,并在此之前沒有出現(xiàn)過=或者:字符。
                    // 那么value的起始位置繼續(xù)往后移動。
                    if (!hasSep && (c == '=' || c == ':')) {
                        hasSep = true;
                    } else {
                        // 當前字符不是=或者:,或者在此之前出現(xiàn)過=或者:字符。那么結(jié)束循環(huán)。
                        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);
        }
    }

會將分割符號兩邊的空格去掉,并且分割符號可以是=,:,空格等。而且=和:的級別比空格分隔符高,即當這兩個都存在的情況下,是按照=/:分割的。可以看到在最后會調(diào)用一個loadConvert方法,該方法主要是做key/value的讀取,并將十六進制的字符進行轉(zhuǎn)換。

總結(jié)

本文闡述了Properties的基本作用以及源碼實現(xiàn),是不是對Properties有了更近一步的認識呢。

以上就是一文帶你全面了解Java Properties類的詳細內(nèi)容,更多關(guān)于Java Properties類的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringBoot使用Flyway進行數(shù)據(jù)庫遷移的實現(xiàn)示例

    SpringBoot使用Flyway進行數(shù)據(jù)庫遷移的實現(xiàn)示例

    Flyway是一個數(shù)據(jù)庫遷移工具,它提供遷移歷史和回滾的功能,本文主要介紹了如何使用Flyway來管理Spring Boot應(yīng)用程序中的SQL數(shù)據(jù)庫架構(gòu),感興趣的可以了解一下
    2023-08-08
  • Spring?question問題小結(jié)

    Spring?question問題小結(jié)

    在AppConfig配置類中,通過@Bean注解創(chuàng)建了Service和Controller的實例,Spring會自動將這些實例納入容器的管理,并處理它們之間的依賴關(guān)系,本文給大家介紹Spring?question問題小結(jié),感興趣的朋友跟隨小編一起看看吧
    2023-10-10
  • MyBatis中SqlSession實現(xiàn)增刪改查案例

    MyBatis中SqlSession實現(xiàn)增刪改查案例

    這篇文章主要介紹了MyBatis中SqlSession實現(xiàn)增刪改查案例,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-03-03
  • 淺談自定義校驗注解ConstraintValidator

    淺談自定義校驗注解ConstraintValidator

    鑒于通用性和普遍性,Spring框架提供了validator組件,通過一些校驗器,可以對一些數(shù)據(jù)進行統(tǒng)一的完整性和有效性等校驗,即簡單又好用
    2021-06-06
  • 詳解springmvc 中controller與jsp傳值

    詳解springmvc 中controller與jsp傳值

    本篇文章主要介紹了springmvc 中controller與jsp傳值,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-07-07
  • Java代碼實現(xiàn)酒店管理系統(tǒng)

    Java代碼實現(xiàn)酒店管理系統(tǒng)

    這篇文章主要為大家詳細介紹了Java代碼實現(xiàn)酒店管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • 詳談Spring對IOC的理解(推薦篇)

    詳談Spring對IOC的理解(推薦篇)

    下面小編就為大家?guī)硪黄斦凷pring對IOC的理解(推薦篇)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • Java多線程的用法詳解

    Java多線程的用法詳解

    本篇文章介紹了,在Java中多線程的用法詳解。需要的朋友參考下
    2013-04-04
  • SpringBoot中加密模塊的使用

    SpringBoot中加密模塊的使用

    本文主要介紹了SpringBoot中加密模塊的使用,包括對稱加密、非對稱加密和哈希加密等,同時還會提供相應(yīng)的代碼示例,感興趣的朋友可以參考一下
    2023-05-05
  • Spring SpringMVC在啟動完成后執(zhí)行方法源碼解析

    Spring SpringMVC在啟動完成后執(zhí)行方法源碼解析

    這篇文章主要介紹了SpringMVC在啟動完成后執(zhí)行方法源碼解析,還是非常不錯的,在這里分享給大家,需要的朋友可以參考下。
    2017-09-09

最新評論