程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java程序中的配置文件的存放和讀取

Java程序中的配置文件的存放和讀取

編輯:關於JAVA

大家可能經常會遇到在Java程序中存取程序配置文件的需求,比如,為了能夠 和不同的數據庫連接,我們經常把數據庫連接的信息存放到屬性文件中,這些信 息一般包括數據庫驅動程序類名、數據庫連接的URL,數據庫的用戶名和口令等等 。為了便於程序的安裝或部署,我們經常會把這些的配置文件存放到程序安裝的 根目錄中。由於Java程序用包來分組類,有時候將這些配置文件放入到讀取它們 的類所在的包目錄中會更好一些。比如,在下面的圖示中,將數據庫配置文件 database.properties放到數據庫讀取類所在的包目錄就是一種比較清晰的存儲方 案:

/-----------其它包目錄

|

|

-------edu.ec.database

|

|---------------ConnectionPool(數據庫連接池類)

|

|---------------Dao(數據庫訪問對象類)

|

|---------------DaoFactory(Dao的工廠類)

|

|---------------database.properties(數據庫配置屬性文件)

|

|---------------RecordSet(記錄集類)

在這種存儲方案中,所有的與數據庫相關的類和配置文件都在同一個包目錄中 ;在開發過程中,配置文件和源文件也按采用這種方式進行組織,這樣會使得程 序的數據庫訪問維護變得相當清晰明了。

大部分開發工具在編譯打包這樣的源文件組織時,會自動將相關配置文件和類 文件放到生成的目標文件夾中或JAR文件中。一般情況下,我們在發布自己的 Java程序時,都是以JAR或WAR形式將程序打包發布,而對應的配置文件也會按照 上述的目錄格式被放到了JAR或WAR文件中,這樣,就實現了配置文件和程序文件 打包在一起發布的目的。

現在的問題是,我們如何讀取位於程序安裝文件中的配置文件的信息?比如, 在上面的圖中, ConnectionPool是一個數據庫連接池類,它需要在系統啟動時自 動讀取存儲在database.properties中的數據庫連接和配置信息,以便設置相關的 數據庫連接。這樣,我們 就需要在程序中測定目前程序安裝或部署的位置,以便 讀取對應的屬性文件。

在很多其他語言編寫的程序中,我們可以利用一些系統提供的API或一些全局 對象獲取目前應用程序運行所在的目錄。比如VB,我們可以使用Application對象 測定當前程序的安裝位置,在Java程序中如何完成類似的任務呢?

Java程序並沒有類似於VB那種全局對象,但如果我們觀察位於上述目錄結構中 的database.properties文件,應該發現其處於應用程序的CLASSPATH中,這樣, 我們就可以使用Java中的類裝載器中的相關的方法,讀出這些配置文件的信息, 該類名為ClassLoader。比如,在上例中,我們可以先得到ConnectinPool的類裝 載器,然後測定ConnectionPool類所在的包路徑,然後利用 ConnectionPool所在 的包目錄讀出database.properties文件的信息,對應的偽代碼如下:

ClassLoader loader=ConnectionPool.class.getClassLoader();

得到ConnectionPool所在的包名;

將包名轉換為對應的目錄名,存入一個名為path的字符串變量中;

調用loader的getResourceAsStream(path+"database.properties"),得到輸 入流

下面是一個可實際運行的樣例代碼片段,它可自動測定傳入的類所在的包目錄 ,返回傳入的屬性文件所代表的輸入流。它還有一個附加的功能:如果屬性文件 直接放到了當前類所在的根目錄(比如位於JAR文件的根目錄或WAR文件的WEB- INF/classes目錄中)、系統的用戶目錄系統、系統其他的類路徑中時,它也可以 找到;當然,如果還是找不到,它將返回null。具體的代碼如下:

public class PropHelper{
/**
*guessPropFile:
*@param cls:和要尋找的屬性文件處於相同的包中的任意的類
*@param propFile:要尋 找的屬性文件名
*/
public static java.io.InputStream guessPropFile(Class cls,String propFile){
try{
//得到類的類裝載器
ding-left: 0px; line-height: 160%; ">ClassLoader loader=cls.getClassLoader();
//先從當前類所處路徑的根目錄中尋找屬性 文件
java.io.InputStream in=loader.getResourceAsStream (propFile);
if(in!=null) return in;
//沒有找到,就從該類所處的包 目錄中查找屬性文件
Package pack=cls.getPackage();
if(pack!=null) {
String packName=pack.getName();
String path="";
if (packName.indexOf(".") < 0 )
path=packName+"/";
else{
int start=0,end=0;
end=packName.indexOf(".");
while(end!=-1) {
path=path+packName.substring(start,end) +"/";
start=end+1;
end=packName.indexOf(".",start);
}
path=path+packName.substring(start)+"/";
}
in=loader.getResourceAsStream(path+propFile);
if(in!=null) return in;
}
//如果沒有找到,再從當前系統的用戶目錄中進行查找
java.io.File f=null;
String curDir=System.getProperty ("user.dir");
f=new java.io.File(curDir,propFile);
if(f.exists()) return new java.io.FileInputStream(f);
//如果還是沒有找到,則從系統 所有的類路徑中查找
String classpath=System.getProperty ("java.class.path");
String[] cps=classpath.split (System.getProperty("path.separator"));
for(int i=0;i < cps.length; i++){
f=new java.io.File(cps[i],propFile);
if (f.exists()) break;
f=null;
}
if(f!=null) return new java.io.FileInputStream(f);
return null;
}catch(Exception e) {throw new RuntimeException(e);}
}
}
"margin-top: 0px;
margin-right: 0px;
margin-bottom: 0px;
margin-left: 0px; padding-top: 0px;
padding-right: 0px; padding-bottom: 0px;
padding-left: 0px;
line-height: 160%; ">

使用舉例:利用上述的方法,可在ConnectionPool中自動查找和 ConnectionPool處於同一個包目錄中的database.properties的輸入流,並利用該 輸入流讀入對應的屬性值的代碼如下:

public class ConnectionPool{
//靜態初始化器,將在 ConnectionPools加載時自動執行
static{
java.util.Properties dbProp=new java.util.Properties();
java.io.InputStream in=PropHelper.guessPropFile (edu.ec.database.ConnectionPool.class,"database.properties");
if (in!=null) dbProp.load(in);
//利用dbProp,為相應的數據源對象設置相關 的屬性,比如C3P0........
}
}
評論

deadcode 寫道程序打包成Jar發布後,應該將配置文件放在jar的當前同級目 錄,訪問調用直接訪問,如

java.util.Properties pro = new java.util.Properties();

InputStream inStream = new java.io.FileInputStream ("database.properties");pro.load(inStream);

如果是打包成WAR發布,則放在適合LZ的方法

現在,guessPropFile可以自動在如下位置中尋找屬性文件:

在未打包的Java程序的類文件所在的根目錄中尋找屬性文件 在打包的JAR程序 的根目錄中尋找屬性文件 在未打包的Java類文件所在的根目錄中對應傳入參數類 所在的包目錄中尋找屬性文件 在打包的JAR文件中對應傳入參數類所在的包目錄 中尋找屬性文件 在未打包及打包的WAR文件夾中的WEB-INF/classes目錄中尋找屬 性文件 在未打包及打包的WAR文件中的WEB-INF/classes目錄中對應傳入參數類所 在的包目錄中尋找屬性文件 在操作系統中的當前登錄用戶的主目錄中尋找屬性文 件 在系統設定的環境變量CLASSPATH所指向的各個目錄中尋找屬性文件

其實,guessPropFile方法還可做的更加智能一些,比如在WAR文件的WEB-INF 文件中尋找屬性文件。如果要完成這個任務,ClassLoader是關鍵類,利用它的 getResource方法,就可以獲得相應程序中的資源的位置,我們可以在它的基礎上 稍加修改就可獲得當前Java程序的運行位置信息,其偽代碼如下:

獲得Class參數的所在的類名

取得該類所在的包名

將包名轉換為路徑

利用getResource得到當前的類文件所在URL

利用URL解析出當前Java程序所在的路徑

具體代碼如下:

public class PropHelper{
//其他方法的定義 //............. /
** *getAppPath需要一個當前程序使用的Java類的class屬性參數,它可以 返回打包過的 *Java可執行文件(jar,war)所處的系統目錄名或非打包Java程 序所處的目錄
*@param cls為Class類型
*@return 返回值為該類所在的 Java程序運行的目錄
*/ public static String getAppPath(Class cls
){ ClassLoader loader=cls.getClassLoader();
String clsName=cls.getName()+".class";
Package pack=cls.getPackage ();
String path=""; if(pack!=null){
String packName=pack.getName ();
clsName=clsName.substring(packName.length()+1);
if (packName.indexOf(".")<0) path=packName+"/";
else{ int start=0,end=0;
end=packName.indexOf(".");
while(end!=-1){ path=path+packName.substring(start,end) +"/";
start=end+1;
end=packName.indexOf(".",start);
} path=path+packName.substring(start)+"/";
} } java.net.URL url =loader.getResource(path+clsName);
String realPath=url.getPath ();
int pos=realPath.indexOf("file:");
if(pos>-1) realPath=realPath.substring(pos+5);
pos=realPath.indexOf (path+clsName);
realPath=realPath.substring(0,pos-1);
if (realPath.endsWith("!")) realPath=realPath.substring (0,realPath.lastIndexOf("/"));
return realPath;
}//getAppPath定義 結束
}//PropHelper類定義結束

在getAppPath方法的幫助下,我們可以測定當前程序運行的路徑是不是包含 WEB-INF/classes路徑信息,如果是,則當前程序就可能是運行在Web環境中,這 樣,就可以對guessPropFile中的代碼進行增加,加入在WEB-INF文件夾尋找屬性 文件的方法。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved