Java中的相對路徑解惑

讓人迷惑的相對路徑

Java 中有一個很容易讓人誤解的問題, 就是路徑問題.
我們來看一段代碼.
項目路徑爲 /home/pathExample, 類的全限定名是 org.haoyifen.PathTest, 類的絕對地址爲 /home/pathExample/src/main/java/org/haoyifen/PathTest.java

public class PathTest {
    @Test
    public void relativePath() {
        Path path = Paths.get("books.xml");
        Path absolutePath = path.toAbsolutePath();
        System.out.println(absolutePath);
    }
}

初學者可能以爲上面輸出的 * /home/pathExample/src/main/java/org/haoyifen/books.xml* , 但其實輸出的是 * /home/pathExample/books.xml* , 也就是相對於項目目錄.
這說明 Java 類中處理相對路徑並不是以當前該類的路徑來進行相對的, 這一點不同於 HTML 中的 js 文件和 CSS 文件的引用.

原因

其實 Java 中處理相對路徑是以 JDK 運行時的屬性”user.dir” 來進行相對的. 我們可以改變”user.dir” 對應的值, 來改變相對路徑轉換爲絕對路徑的值.

    @Test
    public void changeUserDir() {
        //將user.dir對應的值設定爲/home/haoyifen
        System.setProperty("user.dir", "/home/haoyifen");
        Path absolutePath = Paths.get("books.xml").toAbsolutePath();
        //驗證相對路徑轉換爲絕對路徑時, 是以user.dir來進行計算的
        Assert.assertEquals(absolutePath, Paths.get("/home/haoyifen/books.xml"));
    }

在不同的運行環境中, 比如開發時的 IDE, 運行時的命令行或者 WEB 容器, JDK 運行時的屬性”user.dir” 的值的改變規則都是不同的, Java 中絕對不要使用相對路徑來讀取文件, 否則會出現開發時是正常的, 運行時就提示 java.io.FileNotFoundException: books.xml (沒有那個文件或目錄)

類路徑和類加載器

Java中加載文件, 最好是使用類路徑來進行加載, 以下是類路徑的一些規則 (假設類的全限定名爲org.haoyifen.PathTest, 類的根路徑爲/home/pathExample/target/classes)

  • PathTest.class.getResource(“”)
    當前類所在的目錄,file:/home/pathExample/target/classes/org/haoyifen/
  • PathTest.class.getResource(“/”)
    類的跟路徑, file:/home/pathExample/target/classes/
  • PathTest.class.getClassLoader().getResource(“”)
    類的跟路徑, file:/home/pathExample/target/classes/
  • Thread.currentThread().getContextClassLoader().getResource(“”)
    同上, 類的跟路徑, file:/home/pathExample/target/classes/

Spring 框架中的解決辦法

Spring 不僅僅適用於 Java SE, 也適用於 Java EE, Spring 中有個很重要的概念就是 Resource 接口, Resource 是一個抽象於底層實現的資源描述符, 用於獲取底層資源 (可以是文件系統的 File 也可以是網絡 URL) 的輸入流和其他相關信息. 其中使用的最多的實現就是 ClassPathResource, 常見的使用案例有:

  • ClassPathXmlApplicationContext 加載 xml 配置文件啓動 Spring 框架
  • Mybatis-Spring 中加載 Class 路徑中的 mapper.xml 文件來生成 DAO

Resource 最重要的方法如下:

     */
    @Override
    public InputStream getInputStream() throws IOException {
        InputStream is;
        if (this.clazz != null) {
            is = this.clazz.getResourceAsStream(this.path);
        }
        else if (this.classLoader != null) {
            is = this.classLoader.getResourceAsStream(this.path);
        }
        else {
            is = ClassLoader.getSystemResourceAsStream(this.path);
        }
        if (is == null) {
            throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
        }
        return is;
    }

使用的就是 classLoader 來進行加載資源.

總結

  1. Java 中相對路徑是以 System.getProperty(“user.dir”) 來進行相對的.
  2. Java 中絕對不要使用相對路徑來加載文件, user.dir 設定規則在 IDE, 命令行和 WEB 容器中是不同的.
  3. 使用類路徑或者類加載器來加載文件, 這在 Java SE 項目和 WEB 容器中表現都是統一的.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章