最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文帶你全面了解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)

當(dāng)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;
        // 當(dāng)前行信息的緩沖區(qū),大小為1024個字符
        char[] lineBuf = new char[1024];
        // 讀取一行數(shù)據(jù)時候的實際讀取大小
        int inLimit = 0;
        // 讀取的時候指向當(dāng)前字符位置
        int inOff = 0;
        // 字節(jié)流對象
        InputStream inStream;
        // 字符流對象
        Reader reader;

        /**
         * 讀取一行,將行信息保存到{@link lineBuf}對象中,并返回實際的字符個數(shù)
         * 
         * @return 實際讀取的字符個數(shù)
         * @throws IOException
         */
        int readLine() throws IOException {
            // 總的字符長度
            int len = 0;
            // 當(dāng)前字符
            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) {
                        // 如果當(dāng)前長度為0或者是改行是注釋,那么就返回-1。否則返回len的值。
                        if (len == 0 || isCommentLine) {
                            return -1;
                        }
                        return len;
                    }
                }

                // 判斷是根據(jù)字符流還是字節(jié)流讀取當(dāng)前字符
                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++];
                }

                // 如果前一個字符是換行符號,那么判斷當(dāng)前字符是否也是換行符號
                if (skipLF) {
                    skipLF = false;
                    if (c == '\n') {
                        continue;
                    }
                }

                // 如果前一個字符是空格,那么判斷當(dāng)前字符是不是空格類字符
                if (skipWhiteSpace) {
                    if (c == ' ' || c == '\t' || c == '\f') {
                        continue;
                    }
                    if (!appendedLineBegin && (c == '\r' || c == '\n')) {
                        continue;
                    }
                    skipWhiteSpace = false;
                    appendedLineBegin = false;
                }

                // 如果當(dāng)前新的一行,那么進入該if判斷中
                if (isNewLine) {
                    isNewLine = false;
                    // 如果當(dāng)前字符是#或者是!,那么表示該行是一個注釋行
                    if (c == '#' || c == '!') {
                        isCommentLine = true;
                        continue;
                    }
                }

                // 根據(jù)當(dāng)前字符是不是換行符號進行判斷操作
                if (c != '\n' && c != '\r') {
                    // 當(dāng)前字符不是換行符號
                    lineBuf[len++] = c;// 將當(dāng)前字符寫入到行信息緩沖區(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) {
                        // 如果這一行是注釋行,或者是當(dāng)前長度為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;
        // 當(dāng)前key所在位置
        int keyLen;
        // value的起始位置
        int valueStart;
        // 當(dāng)前字符
        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) {
                // 獲取當(dāng)前字符
                c = lr.lineBuf[keyLen];
                // 如果當(dāng)前字符是=或者是:,而且前一個字符不是轉(zhuǎn)義字符,那么就表示key的描述已經(jīng)結(jié)束
                if ((c == '=' || c == ':') && !precedingBackslash) {
                    // 指定value的起始位置為當(dāng)前keyLen的下一個位置
                    valueStart = keyLen + 1;
                    // 并且指定,去除空格
                    hasSep = true;
                    break;
                } else if ((c == ' ' || c == '\t' || c == '\f') && !precedingBackslash) {
                    // 如果當(dāng)前字符是空格類字符,而且前一個字符不是轉(zhuǎn)義字符,那么表示key的描述已經(jīng)結(jié)束
                    // 指定value的起始位置為當(dāng)前位置的下一個位置
                    valueStart = keyLen + 1;
                    break;
                }
                // 如果當(dāng)前字符為'',那么跟新是否是轉(zhuǎn)義號。
                if (c == '\') {
                    precedingBackslash = !precedingBackslash;
                } else {
                    precedingBackslash = false;
                }
                keyLen++;
            }

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

會將分割符號兩邊的空格去掉,并且分割符號可以是=,:,空格等。而且=和:的級別比空格分隔符高,即當(dāng)這兩個都存在的情況下,是按照=/:分割的??梢钥吹皆谧詈髸{(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)文章

  • 基于Java編寫簡單的Excel工具類

    基于Java編寫簡單的Excel工具類

    這篇文章主要為大家詳細介紹了如何基于Java編寫簡單的Excel工具類,文中的示例代碼講解詳細,具有一定的借鑒價值,有需要的小伙伴可以參考下
    2024-02-02
  • 詳解Feign的實現(xiàn)原理

    詳解Feign的實現(xiàn)原理

    Feign是Netflix開發(fā)的聲明式、模板化的HTTP客戶端, Feign可以幫助我們更快捷、優(yōu)雅地調(diào)用HTTP API
    2021-06-06
  • 關(guān)于Idea卡在Resolving Maven dependencies的解決方案

    關(guān)于Idea卡在Resolving Maven dependencies的解決方案

    本文詳細介紹了關(guān)于Idea卡在Resolving Maven dependencies的解決方案,文中通過圖文結(jié)合的形式給大家介紹的非常詳細,對大家解決問題有一定的幫助,需要的朋友可以參考下
    2024-02-02
  • 詳解查看JAVA API及JAVA源碼的方法

    詳解查看JAVA API及JAVA源碼的方法

    這篇文章主要介紹了查看JAVA API及JAVA源碼的方法,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-02-02
  • Java如何實現(xiàn)讀取txt文件內(nèi)容并生成Word文檔

    Java如何實現(xiàn)讀取txt文件內(nèi)容并生成Word文檔

    本文主要介紹了通過Java實現(xiàn)讀取txt文件中的內(nèi)容,并將內(nèi)容生成Word文檔。文章的代碼非常詳細,具有一定的學(xué)習(xí)價值,感興趣的小伙伴可以了解一下
    2021-12-12
  • 優(yōu)雅地在Java應(yīng)用中實現(xiàn)全局枚舉處理的方法

    優(yōu)雅地在Java應(yīng)用中實現(xiàn)全局枚舉處理的方法

    這篇文章主要給大家介紹了關(guān)于如何優(yōu)雅地在Java應(yīng)用中實現(xiàn)全局枚舉處理的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • springboot連接oracle全流程

    springboot連接oracle全流程

    這篇文章主要介紹了springboot連接oracle全流程,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • RabbitMQ消息中間件示例詳解

    RabbitMQ消息中間件示例詳解

    這篇文章主要給大家介紹了關(guān)于RabbitMQ消息中間件的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一學(xué)習(xí)學(xué)習(xí)吧
    2018-12-12
  • java更改圖片大小示例分享

    java更改圖片大小示例分享

    這篇文章主要介紹了java更改圖片大小示例,方法中指定路徑 ,舊文件名稱 ,新文件名稱,n 改變倍數(shù)就可以完成更改圖片大小,需要的朋友可以參考下
    2014-03-03
  • SpringMvc框架的簡介與執(zhí)行流程詳解

    SpringMvc框架的簡介與執(zhí)行流程詳解

    MVC是一種軟件設(shè)計典范,用一種業(yè)務(wù)邏輯、數(shù)據(jù)、界面顯示分離的方法組織代碼,將業(yè)務(wù)邏輯聚集到一個組件里面,在改進和個性化定制界面及用戶交互的同時,不需要重新編寫業(yè)務(wù)邏輯,MVC分層有助于管理和架構(gòu)復(fù)雜的應(yīng)用程序
    2021-06-06

最新評論

平南县| 东阿县| 惠水县| 阳曲县| 铁岭市| 山西省| 东台市| 东乡| 砚山县| 德江县| 鲁山县| 宁海县| 庐江县| 浦江县| 莱西市| 鄂托克前旗| 哈巴河县| 博湖县| 康平县| 万宁市| 临夏市| 灵川县| 民县| 贺兰县| 桐乡市| 赤峰市| 南漳县| 承德市| 汤原县| 武宣县| 安塞县| 扎囊县| 科技| 体育| 桓台县| 茌平县| 无为县| 伊川县| 奉新县| 东源县| 什邡市|