最近在做項目的時候,自己寫了一些配置參數的讀取,將配置文件放到具體的位置,然后讓程序根據當前類的路徑尋找配置文件的路徑,但是,發現eclipse的開發壞境下是可以順利讀取到指定路徑下的配置文件中的配置參數的,
但是當將項目放到Tomcat下 或者 將項目打包成可執行jar包之后,編譯后的class文件卻讀取不到了開發環境下尋找的配置文件了。
如果在 .java 文件中直接寫// public static String Config = "config.properties"; 則該路徑指向的就是項目的 src 的同級目錄(直接將配置文件放到項目的根目錄下)
經過查找資料和進行驗證,現將讀取class文件相對路徑下配置文件的方法匯總如下:
方法一:使用System獲取路徑
方法二:使用當前類的ProtectionDomain或者ClassLoader獲取路徑
方法三:使用Thread獲取路徑
方法一:
示例:
public static final String URLConfig = System.getProperty("user.dir").replace("bin", "webapps")+"/URLConfig.properties";//這種是將配置文件放到Tomcat的webapps的目錄下
其中的 System.getProperty("user.dir") 為獲取用戶當前工作目錄
java的System.getProperty()方法可以獲取的值


獲取的代碼示例:
public class SystemProperty { public static void main(String args[]) { System.out.println("java_vendor:" + System.getProperty( "java.vendor" )); System.out.println("java_vendor_url:" + System.getProperty("java.vendor.url" )); System.out.println("java_home:" + System.getProperty( "java.home" )); System.out.println("java_class_version:" + System.getProperty("java.class.version" )); System.out.println("java_class_path:" + System.getProperty("java.class.path" )); System.out.println("os_name:" + System.getProperty( "os.name" )); System.out.println("os_arch:" + System.getProperty( "os.arch" )); System.out.println("os_version:" + System.getProperty( "os.version" )); System.out.println("user_name:" + System.getProperty( "user.name" )); System.out.println("user_home:" + System.getProperty( "user.home" )); System.out.println("user_dir:" + System.getProperty( "user.dir" )); System.out.println("java_vm_specification_version:" + System.getProperty("java.vm.specification.version" )); System.out.println("java_vm_specification_vendor:" + System.getProperty("java.vm.specification.vendor" )); System.out.println("java_vm_specification_name:" + System.getProperty("java.vm.specification.name" )); System.out.println("java_vm_version:" + System.getProperty("java.vm.version" )); System.out.println("java_vm_vendor:" + System.getProperty("java.vm.vendor" )); System.out .println("java_vm_name:" + System.getProperty( "java.vm.name" )); System.out.println("java_ext_dirs:" + System.getProperty("java.ext.dirs" )); System.out.println("file_separator:" + System.getProperty("file.separator" )); System.out.println("path_separator:" + System.getProperty("path.separator" )); System.out.println("line_separator:" + System.getProperty("line.separator" )); }
上面示例引用的博客地址:https://blog.csdn.net/capmiachael/article/details/51895823
方法二:
示例1:
public static String getMyDIR(){//獲取當前類文件的絕對路徑 String jarWholePath = ConfigerPraram.class.getProtectionDomain().getCodeSource().getLocation().getFile(); try { //保險起見,將路徑進行decode轉碼 jarWholePath = java.net.URLDecoder.decode(jarWholePath, "UTF-8"); } catch (UnsupportedEncodingException e) { System.out.println(e.toString()); } //獲取jar包的上級目錄 String jarPath = new File(jarWholePath).getParentFile().getAbsolutePath(); return jarPath; }
示例2:
/** * 獲取項目所在路徑 * * @return */ public static String getRealPath() {
//通過類加載器獲取jar包的絕對路徑 String realPath = MyPath.class.getClassLoader().getResource("") .getFile(); java.io.File file = new java.io.File(realPath); realPath = file.getParentFile().getAbsolutePath(); //獲取jar包的上級目錄
try {
//路徑decode轉碼 realPath = java.net.URLDecoder.decode(realPath, "utf-8"); } catch (Exception e) { e.printStackTrace(); }
return realPath ;
}
方法三:(該方法還未做驗證,引用博客:https://blog.csdn.net/z69183787/article/details/22774537)
Thread.currentThread().getContextClassLoader().getResource("")來得到當前的classpath的絕對路徑的URI表示法
Application可以通過new FileInputStream("xx.properties");直接在classes一級獲取。關鍵是有時我們需要通過web修改配置文件,我們不 能將路徑寫死了。經過測試覺得有以下心得:
1.servlet中讀寫。如果運用Struts 或者Servlet可以直接在初始化參數中配置,調用時根據servlet的getRealPath("/")獲取真實路徑,再根據String file = this.servlet.getInitParameter("abc");獲取相對的WEB-INF的相對路徑。
例:
InputStream input =Thread.currentThread().getContextClassLoader().getResourceAsStream("abc.properties");
Properties prop = new Properties();
prop.load(input);
input.close();
prop.setProperty("abc", “test");
prop.store(new FileOutputStream(path), “–test–");
out.close();
2.直接在jsp中操作,通過jsp內置對象獲取可操作的絕對地址。
例:
// jsp頁面
String path = pageContext.getServletContext().getRealPath("/");
String realPath = path+"/WEB-INF/classes/abc.properties";
//java 程序
InputStream in = getClass().getClassLoader().getResourceAsStream("abc.properties"); // abc.properties放在webroot/WEB-INF/classes/目錄下
prop.load(in);
in.close();
OutputStream out = new FileOutputStream(path); // path為通過頁面傳入的路徑
prop.setProperty("abc", “abcccccc");
prop.store(out, “–test–");
out.close();
3.只通過Java程序操作資源文件
InputStream in = new FileInputStream("abc.properties"); // 相對路徑,項目下的路徑
OutputStream out = new FileOutputStream("abc.properties");
下面的參考解釋引用於博客:https://www.cnblogs.com/gaoxing/p/4703412.html
打個簡單的比方,你一個WEB程序,發布到Tomcat里面運行。
首先是執行Tomcat org.apache.catalina.startup.Bootstrap類,這時候的類加載器是ClassLoader.getSystemClassLoader()。
而我們后面的WEB程序,里面的jar、resources都是由Tomcat內部來加載的,所以你在代碼中動態加載jar、資源文件的時候,首先應該是使用Thread.currentThread().getContextClassLoader()。如果你使用Test.class.getClassLoader(),可能會導致和當前線程所運行的類加載器不一致(因為Java天生的多線程)。
Test.class.getClassLoader()一般用在getResource,因為你想要獲取某個資源文件的時候,這個資源文件的位置是相對固定的。
java的類加載機制(jvm規范)是委托模型,簡單的說,如果一個類加載器想要加載一個類,首先它會委托給它的parent去加載,如果它的所有parent都沒有成功的加載那么它才會自己親自來,有點兒像兒子使喚老子的感覺。
如果你使用Test.class.getClassLoader(),可能會導致和當前線程所運行的類加載器不一致 :Class.getClassLoader() returns the class loader for the class. Some implementations may use null to represent the bootstrap class loader. This method will return null in such implementations if this class was loaded by the bootstrap class loader.
