Java IO 操作底層皆需絕對路徑。所謂「相對路徑」只是 API 幫你根據「當前工作目錄」或「ClassPath」拼湊而成的便利寫法。理解這點,路徑問題就解決一半了。
String webRoot = getServletContext().getRealPath("/");
最標準、最可靠的方式,直接拿到部署後的應用根目錄實體路徑。
方案 1:利用類別載入機制(適用於 Class 在 WEB-INF/classes)
URL url = MyClass.class.getClassLoader().getResource("");
// 取得 ClassPath 根目錄 URI,再手動推導 WebRoot
缺點: 若類別被打包進 JAR,此法失效。
方案 2:Spring 風格,啟動時將路徑寫入 System Properties(推薦)
web.xml 定義 <context-param> webAppRootKey=webapp.root </context-param>ServletContextListener,於 contextInitialized 取得 getRealPath("/") 並 System.setProperty("webapp.root", path)。System.getProperty("webapp.root") 即得路徑。| 方法呼叫 | 取得內容 | 範例輸出 |
|---|---|---|
MyClass.class.getResource("") | 當前類別 .class 所在目錄 URI(不含檔名) | file:/D:/proj/WebRoot/WEB-INF/classes/com/pkg/ |
MyClass.class.getResource("/") | ClassPath 根目錄 URI | file:/D:/proj/WebRoot/WEB-INF/classes/ |
Thread.currentThread().getContextClassLoader().getResource("") | 當前執行緒上下文 ClassLoader 的 ClassPath 根目錄 URI | 同上 |
MyClass.class.getClassLoader().getResource("") | 同上(系統類別載入器) | 同上 |
System.getProperty("user.dir") | JVM 啟動工作目錄(通常是啟動腳本所在目錄,如 Tomcat 的 bin/) | E:\apache-tomcat\bin |
推薦: 使用 Thread.currentThread().getContextClassLoader().getResource("") 取得標準 ClassPath URI,最穩健。
ServletContext.getRealPath("/")(棄用 request.getRealPath("/"))new File("com/test.java") 相對 ClassPath 即可(預設即 src 目錄)。String path = getServletContext().getRealPath("/");
String base = path.substring(0, path.lastIndexOf("\\WebRoot") + 1);
File propFile = new File(base + "doc/db.properties");
getResourceAsStream)與「檔案系統資源」(File),前者可讀 JAR 內資源,後者不可。user.dir 指向專案根目錄,與伺服器環境不同,測試代碼需兼容。掌握這些模式,路徑問題不再是開發阻礙。