2020国产成人精品视频,性做久久久久久久久,亚洲国产成人久久综合一区,亚洲影院天堂中文av色

分享

正確使用Java Properties - Java綜合 - Java - JavaEye...

 squarecome 2011-01-20
最近賦閑在家閑的蛋疼,找工作也不順利,就安靜下來(lái)學(xué)一些常用開(kāi)源項(xiàng)目,在翻struts2的時(shí)候看到讀取properties配置文件是自己定義的reader來(lái)讀取,因?yàn)橹吧习嗟臅r(shí)候常常使用到properties的讀寫,對(duì)于jdk本身的properties在保存的時(shí)候會(huì)把注釋忽略掉這點(diǎn)深惡痛絕,一直想重新寫一個(gè)properties文件讀寫的工具類,但是大致翻了一下properties的代碼和文檔,發(fā)現(xiàn)properties的規(guī)則挺多,沒(méi)有幾天時(shí)間怕是難以完成就一直擱下了。這次看到struts2的代碼就想拿來(lái)借鑒一下,于是就把properties的東西讀了一遍,發(fā)覺(jué)很多東西是之前忽略甚至不知道的,于是記下和兄弟們共享,如有錯(cuò)歡迎指正,概念頗多,容易暈頭,建議找頭腦清醒的時(shí)候看。
JDK Properties核心在讀取配置文件的
Java代碼 復(fù)制代碼
  1. private void load0 (LineReader lr) throws IOException  
方法上。其中傳入的參數(shù)LineReader類是Properties的內(nèi)部類,用來(lái)讀取一個(gè)邏輯行(這兒就不詳細(xì)介紹了,它會(huì)讀取一個(gè)邏輯行并且忽略掉邏輯行行首的所有空白字符和換行字符)。
load0方法的JDK文檔總結(jié)如下,這也是后續(xù)的幾個(gè)重要的概念的出處:
1.注釋符為:'#'或者'!'??瞻鬃址麨椋? ', '\t', '\f'。key/value分隔符為:'='或者':'。行分隔符為:'\r','\n','\r\n'。
2.自然行是使用行分隔符或者流的結(jié)尾來(lái)分割的行。邏輯行可能分割到多個(gè)自然行中,使用反斜杠'\'來(lái)連接多個(gè)自然行。
3.注釋行是使用注釋符作為首個(gè)非空白字符的自然行。
4.空白字符的自然行會(huì)被認(rèn)為是空行而被忽略。
5.properties文件的key為從首個(gè)非空白字符開(kāi)始直到(但不包括)首個(gè)非轉(zhuǎn)義的'=', ':'或者非行結(jié)束符的空白字符為止。
6.key后面的第一個(gè)非空白字符如果是”=”或者”:”,那么這個(gè)字符后面所有空白字符都會(huì)被忽略掉。
7.可以使用轉(zhuǎn)義序列表示key和value(當(dāng)然此處的字符轉(zhuǎn)義序列和unicode的轉(zhuǎn)義有一些差別,jdk文檔都有列出來(lái))。
properties是一個(gè)包含了key、value對(duì)的文本文檔,key,value的界定是正確讀取properties的關(guān)鍵,那么key、value是如何界定的呢?上面第5點(diǎn)是對(duì)key的不完全界定但是并未涉及到value,這些,都只有從源碼當(dāng)中來(lái)尋找答案。
load0源碼和注解如下:
Java代碼 復(fù)制代碼
  1. private void load0(LineReader lr) throws IOException {   
  2.         char[] convtBuf = new char[1024];   
  3.         //行的長(zhǎng)度   
  4.         int limit;   
  5.         //key的長(zhǎng)度   
  6.         int keyLen;   
  7.         //value的開(kāi)始點(diǎn)   
  8.         int valueStart;   
  9.         //當(dāng)前讀取的字符   
  10.         char c;   
  11.         //是否是key/value的分隔符   
  12.         boolean hasSep;   
  13.         //前一個(gè)字符是否是反斜杠   
  14.         boolean precedingBackslash;   
  15.         //把通過(guò)LineReader讀取來(lái)的邏輯行進(jìn)行遍歷,一個(gè)個(gè)char的進(jìn)行處理。   
  16.         while ((limit = lr.readLine()) >= 0) {   
  17.             c = 0;   
  18.             keyLen = 0;   
  19.             valueStart = limit;   
  20.             hasSep = false;   
  21.             precedingBackslash = false;   
  22.             //循環(huán)獲取key的長(zhǎng)度   
  23.             while (keyLen < limit) {   
  24.                 c = lr.lineBuf[keyLen];   
  25.                 //當(dāng)字符為key/value分隔符:'='或':'并且前一個(gè)字符不是反斜杠的時(shí)候,key長(zhǎng)度讀取結(jié)束,并且把hasSep設(shè)置為true,break。   
  26.                 if ((c == '=' || c == ':') && !precedingBackslash) {   
  27.                     valueStart = keyLen + 1;   
  28.                     hasSep = true;   
  29.                     break;   
  30.                 }   
  31.                 //當(dāng)字符為空白字符' '或'\t'或'\f'并且前一個(gè)字符不是反斜杠的時(shí)候,key長(zhǎng)度讀取結(jié)束,break。   
  32.                 else if ((c == ' ' || c == '\t' || c == '\f') && !precedingBackslash) {   
  33.                     valueStart = keyLen + 1;   
  34.                     break;   
  35.                 }   
  36.                 //當(dāng)連續(xù)存在奇數(shù)個(gè)反斜杠的時(shí)候, precedingBackslash為true。   
  37.                 if (c == '\\') {   
  38.                     precedingBackslash = !precedingBackslash;   
  39.                 } else {   
  40.                     precedingBackslash = false;   
  41.                 }   
  42.                 keyLen++;   
  43.             }   
  44.             //循環(huán)獲取value開(kāi)始的位置   
  45.             while (valueStart < limit) {   
  46.                 c = lr.lineBuf[valueStart];   
  47.                 //如果字符不為所有的空白字符:' ', '\t', '\f'的時(shí)候   
  48.                 if (c != ' ' && c != '\t' && c != '\f') {   
  49.                     //如果前面不是key/value的分隔符,而是空白字符,而該字符是key/value分隔符   
  50.                     if (!hasSep && (c == '=' || c == ':')) {   
  51.                         hasSep = true;   
  52.                     } else {   
  53.                         //結(jié)束讀取   
  54.                         break;   
  55.                     }   
  56.                 }   
  57.                 valueStart++;   
  58.             }   
  59.             //loadConvert是進(jìn)行字符串轉(zhuǎn)義的方法,就不用關(guān)心了。   
  60.             String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);   
  61.             String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);   
  62.             put(key, value);   
  63.         }   
  64.     }  


通過(guò)如上的代碼可以看出,key/value分割符'=', ':'與空白字符:' ', '\t', '\f'是區(qū)分key、value的關(guān)鍵:
key的界定為:邏輯行中,從首個(gè)非空白字符開(kāi)始直到(但不包括)首個(gè)非轉(zhuǎn)義的'=', ':'或者非行結(jié)束符的空白字符為止。(和前面第5點(diǎn)基本一致)
value的界定為:邏輯行中,非轉(zhuǎn)義的key/value分隔符(此處不僅僅包括'=',':',還包括' ', '\t', '\f')后面的第一個(gè)非空白字符(非' ', '\t', '\f'字符)開(kāi)始到邏輯行結(jié)束的所有字符。


另外key、value還有如下特征:
1.因?yàn)長(zhǎng)ineReader是讀取的邏輯行,所以key、value中可以包含多個(gè)自然行。
2.在“循環(huán)獲取key的長(zhǎng)度”的代碼中可以看到處理key/value分隔符的方式和處理空白字符的方式很相似(除了在發(fā)現(xiàn)處理的字符為key/value分隔符的時(shí)候會(huì)把 hasSep變量設(shè)置為true)。而這表明:
如果空白字符后續(xù)沒(méi)有key/value分隔符(“=”或者“:”),那么該空白字符會(huì)被當(dāng)作key/value分隔符,從分隔符后的第一個(gè)非空白字符起到邏輯行結(jié)束所有的字符都當(dāng)作是value。也就是說(shuō):“key1 value1”,讀取出來(lái)之后的key和value分別為”key1”, “value1”。
如果空白字符后續(xù)有key/value分隔符(“=”或者“:”),那么該空白字符會(huì)被忽略,key/value分隔符后的第一個(gè)非空白字符起到邏輯行結(jié)束所有的字符都當(dāng)作是value。也就是說(shuō):”key1 :value1”,讀取出來(lái)之后的key和value分別為”key1”和”value1”,而不是”key1”和”:value1”。

另外,在讀xwork的com.opensymphony.xwork2.util.PropertiesReader類的時(shí)候發(fā)現(xiàn),它的實(shí)現(xiàn)和JDK的Properties實(shí)現(xiàn)有出入,也就是說(shuō),如果JDK的Properties是規(guī)范的話,那么xwork的properties讀取類是有bug的。測(cè)試類如下(注釋掉的Assert才能通過(guò)junit):
Java代碼 復(fù)制代碼
  1. public class PropertiesTest {   
  2.     @Test  
  3.     public void testLoad() throws IOException {   
  4.         File f = new File(getClass().getResource(".").getPath(), "test.properties");   
  5.   
  6.         InputStream in = null;   
  7.         try {   
  8.             //java properties   
  9.             in = new FileInputStream(f);   
  10.             Properties props = new Properties();   
  11.             props.load(in);   
  12.             String s1 = props.getProperty("key");   
  13.             Assert.assertEquals("value#with", s1);   
  14.             String s2 = props.getProperty("comments");   
  15.             Assert.assertEquals("", s2);   
  16.         } finally {   
  17.             if (in != null)   
  18.                 try {   
  19.                     in.close();   
  20.                 } catch (IOException e) {   
  21.                     e.printStackTrace();   
  22.                 }   
  23.         }   
  24.   
  25.         try {   
  26.             //xwork properties   
  27.             in = new FileInputStream(f);   
  28.             Reader reader = new InputStreamReader(in);   
  29.             PropertiesReader pr = new PropertiesReader(reader);   
  30.             while (pr.nextProperty()) {   
  31.                 String name = pr.getPropertyName();   
  32.                 String val = pr.getPropertyValue();   
  33.                 if ("key".equals(name)) {   
  34.                     Assert.assertEquals("value#with", val);   
  35.                     //Assert.assertEquals("valuecomments", val);   
  36.                 }   
  37.                 if ("comments".equals(name)) {   
  38.                     Assert.assertEquals("", val);   
  39.                     //Assert.assertEquals(null, val);   
  40.                 }   
  41.             }   
  42.         } finally {   
  43.             if (in != null)   
  44.                 try {   
  45.                     in.close();   
  46.                 } catch (IOException e) {   
  47.                     e.printStackTrace();   
  48.                 }   
  49.         }   
  50.     }   
  51. }  


test.properties的內(nèi)容如下:
Java代碼 復(fù)制代碼
  1. key=value\   
  2. #with   
  3. comments  



好了,清楚properties的使用規(guī)則了,如果我們需要自己寫一個(gè)實(shí)現(xiàn)在保存properties的時(shí)候注釋不被忽略掉,而且按照原來(lái)的行數(shù)來(lái)保存的工具類的話,就會(huì)清晰很多了。本來(lái)想把這個(gè)工具寫一下,但是寫代碼加調(diào)試實(shí)在太費(fèi)時(shí)間,等到用的時(shí)候再來(lái)寫吧。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多