用類加載器的5種方式讀取.properties文件


    

用類加載器的5中形式讀取.properties文件(這個.properties文件一般放在src的下面)

 

用類加載器進行讀取:這里采取先向大家講讀取類加載器的幾種方法;然后寫一個例子把幾種方法融進去,讓大家直觀感受。最后分析原理。(主要是結合所牽涉的方法的源代碼的角度進行分析)

這里先介紹用類加載器讀取的幾種方法:

1.任意類名.class.getResourceAsStream("/文件所在的位置");【文件所在的位置從包名開始寫】

2.和.properties文件在同一個目錄下的類名.class.getResourceAsStream("文件所在的位置");【文件所在的位置從包名開始寫,注意這里和上面的相比較少了一個斜杠/】

  當然你也可以寫成跟1一樣的形式即:任意類名.class.getResourceAsStream("/文件所在的位置");

3.任意類名.class.getClassLoader().getResourceAsStream("文件所在的位置");【文件所在的位置從包名開始寫】

4.任意類名.class.getClassLoader().getResource("文件所在的位置").openStream();【文件所在的位置從包名開始寫】

5.任意類名.class.getClassLoader().getResource("文件所在的位置")..openConnection().getInputStream();【文件所在的位置從包名開始寫】

//一個例子,說明上述5中方法的用法。

上面圖片中的各個紅色矩形就是我要讀取的properties文件。主要是兩類。一類直接放在src下面。另一類是放在某個文件夾下面.

//f.properties文件的內容如下圖所示;

 

//上述五種情況說明的代碼如下:

 1 package com.qls.commonclass;
 2 
 3 import java.io.IOException;
 4 import java.io.InputStream;
 5 import java.util.Properties;
 6 
 7 import com.qls.counter.Ok;
 8 
 9 /**
10  * 分別用類加載器的5種方法讀取f.properties文件。
11  * @author 秦林森
12  *
13  */
14 public class Test6 {
15 
16     public static void main(String[] args) throws IOException {
17         // TODO Auto-generated method stub
18         /**第一種情形獲取輸入流。
19          * 任意類名.class.getResourceAsStream("/文件所在的位置");【文件所在的位置從包名開始寫】
20          * @param args
21          */
22         //獲取輸入流
23         InputStream in = Test.class.getResourceAsStream("/com/qls/counter/f.properties");
24         /**
25          * 第二種情形獲取輸入流。
26          * 和.properties文件在同一個目錄下的類名.class.getResourceAsStream("文件所在的位置");
27          * 【文件所在的位置從包名開始寫,注意這里和上面的相比較少了一個斜杠/】
28          * 這里隨便選擇一個與:f.properties在同一個目錄下的類比如Ok這個類吧!
29          * 這里你自然也可以寫成跟第一種情況一樣的形式:
30          * 即:
31          * InputStream in2 = Ok.class.getResourceAsStream("/com/qls/counter/f.properties");
32          * 因為第一種情況是針對任意一個類而言的公式。
33          */
34         InputStream in2 = Ok.class.getResourceAsStream("f.properties");
35         /**
36          * 第三種情形獲取輸入流:
37          * 任意類名.class.getClassLoader().getResourceAsStream("文件所在的位置");
38          * 【文件所在的位置從包名開始寫】
39          */
40         InputStream in3 = Test2.class.getClassLoader().getResourceAsStream("com/qls/counter/f.properties");
41         /**
42          * 第四中情形獲取輸入流:
43          * 任意類名.class.getClassLoader().getResource("文件所在的位置").openStream();
44          * 【文件所在的位置從包名開始寫】
45          */
46         InputStream in4 = Test4.class.getClassLoader().getResource("com/qls/counter/f.properties").openStream();
47         /**
48          * 第五種情形獲取輸入流:
49          * .任意類名.class.getClassLoader().getResource("文件所在的位置").openConnection().getInputStream();
50          * 【文件所在的位置從包名開始寫】
51          */
52         InputStream in5 = Test5.class.getClassLoader().getResource("com/qls/counter/f.properties").openConnection().getInputStream();
53         //創建Properties
54         Properties prop=new Properties();
55         //把輸入流in加載到prop中
56         /*
57          * 驗證上述5中輸入流是否成立。只需帶入prop.load(InputStream inputStream);驗證即可。
58          * 也就是:
59          * prop.load(in);
60          * prop.load(in2);
61          * prop.load(in3);
62          * prop.load(in4);
63          * prop.load(in5);
64          */
65         prop.load(in5);
66         System.out.println("sixi="+prop.getProperty("sixi"));
67         System.out.println("ouyangfeng="+prop.getProperty("ouyangfeng"));
68         System.out.println("rape="+prop.getProperty("farm"));
69     }
70 
71 }/*
72 Output:
73 sixi=river
74 ouyangfeng=masses
75 farm=flower
76 **///:~

上述5中方法的原理分析。

首先看看Class中的resolveName(String name)究竟是干什么的。源碼如下所示:

 1  private String resolveName(String name) {
 2         if (name == null) {
 3             return name;
 4         }
 5         if (!name.startsWith("/")) {
 6             Class<?> c = this;
 7             while (c.isArray()) {
 8                 c = c.getComponentType();
 9             }
10             String baseName = c.getName();
11             int index = baseName.lastIndexOf('.');
12             if (index != -1) {
13                 name = baseName.substring(0, index).replace('.', '/')
14                     +"/"+name;
15             }
16         } else {
17             name = name.substring(1);
18         }
19         return name;
20     }

下面我把這個源碼講的內容翻譯人類語言:

給任意一個字符串name,如果該name是以/開始的,則該函數返回的是:去掉/這個字符的字符串。(如name="/ouyangfeng" 則調用該函數之后得到的結果是:name=ouyangfeng)。
如果該name這個字符串不是以/開始的,則該函數返回的結果是調用這個函數類所在的包名+name組成的字符串(例如假設Test5所在的包名是:com.qls.mount 。則:Test5.class.resolveName("ouyangfeng");返回結果是:com/qls/mount/ouyangfeng)

也就是幫助文檔講述的:

  • If the name begins with a '/' ('\u002f'), then the absolute name of the resource is the portion of the name following the '/'.
  • Otherwise, the absolute name is of the following form:
    modified_package_name/name

    Where the modified_package_name is the package name of this object with '/' substituted for '.' ('\u002e'). 

  • 上述英文我簡要翻譯一下:如果name是以一個/開頭,則這個資源的絕對name就是:name中/之后的部分內容。
  • 否則:這這個絕對name就是如下形式。包名/name,把這里包名中的.用/代替掉。【如:com.qls.river把.用/代替掉就是:com/qls/river】

然后我們再看看Class類中的getResourceAsStream(String name)的源碼和ClassLoader中的getResourceAsStream(String name)中的源碼。

 

Class類中的getResourceAsStream(String name)的源碼如下:

1  public InputStream getResourceAsStream(String name) {
2         name = resolveName(name);//注意這里有一個resolveName(String name)方法,根據上述的分析,易知道這個源碼的意思.
3         ClassLoader cl = getClassLoader0();
4         if (cl==null) {
5             // A system class.
6             return ClassLoader.getSystemResourceAsStream(name);
7         }
8         return cl.getResourceAsStream(name);
9     }

ClassLoader中的getResourceAsStream(String name)中的源碼如下:

1  public InputStream getResourceAsStream(String name) {
2         URL url = getResource(name);
3         try {
4             return url != null ? url.openStream() : null;//這句代碼的意思是:如果url不是null時返回的是:url.openStream(),反之如果url為null則返回null.
5         } catch (IOException e) {
6             return null;
7         }
8     }

通過這Class.resolveName(String name)中的源代碼和ClassLoader.getResourceAsStream(String name)中的源代碼以及Class.getResourceAsStream(String name)中的原代碼我們易知道上述五種情況是怎么來的。無需記憶。

只需學會數學推理即可。

大家在看源碼是:發現Class.resolveName(String name)這個方法是private的,你用普通方法根本調用不了,下面我順便提一下:如何調用這個方法。以便大家可以更好的理解這個方法所講的意思。

 1 package com.qls.commonclass;
 2 
 3 import java.lang.reflect.InvocationTargetException;
 4 import java.lang.reflect.Method;
 5 
 6 /**
 7  * 用反射調用ClassLoade中的 private String resolveName(String name)
 8  * 驗證這個方法所講的意思。
 9  * @author 秦林森
10  *
11  */
12 public class Test7 {
13 
14     public static void main(String[] args) throws Exception{
15         // TODO Auto-generated method stub
16         //得到這個方法。
17         Method method = Class.class.getDeclaredMethod("resolveName", new Class[]{String.class});
18         //由於這個方法是private,所以要獲取這個方法的訪問權限
19         method.setAccessible(true);
20         //寫一個實例,以便調用這個方法。
21         
22         Object obj = Test7.class;//Test這個類所在的包是:com.qls.commonclass
23         //調用這個方法
24         String invoke = (String) method.invoke(obj, new Object[]{"ouyangfeng"});
25         String invoke2 = (String) method.invoke(obj, new Object[]{"/ouyangfeng"});
26         System.out.println("invoke="+invoke);
27         System.out.println("invoke2="+invoke2);
28         
29     }
30 
31 }/*
32 Output:
33 invoke=com/qls/commonclass/ouyangfeng
34 invoke2=ouyangfeng
35 由此可以證明了:以/開頭的字符串"/ouyangfeng"調用resolveName(String name)
36 這個方法之后返回的結果是:ouyangfeng
37 不以/開頭的字符串:"ouyangfeng"返回的結果是:調用這個方法的包名/name
38 【在本例中是Test7調用resolveName(String name),而Test7所在的包是:com.qls.commonclass
39 所以返回結果是:com/qls/commonclass/ouyangfeng】
40 
41 *///:~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM