首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 取得專案路徑、Classpath 與資源檔案完整指南

     編輯:Java 相關知識

前言

在 Java 開發中,正確取得檔案路徑是常見痛點:IDE 執行、JAR 打包部署、單元測試、Web 容器等環境下路徑表現各異。本文系統整理六種常見路徑取得場景,提供標準、可攜的最佳實踐。

一、核心 API 對照表

需求場景推薦 API回傳型別適用環境
目前類別所在目錄 (編譯後 .class 位置)ThisClass.class.getResource("").getPath()String所有
Classpath 根目錄 (src/main/resources 編譯後)ThisClass.class.getResource("/").getPath()String所有
專案根目錄 (Maven/Gradle 專案根目錄)new File("").getCanonicalPath() 或 System.getProperty("user.dir")StringIDE、命令列、測試
讀取 Classpath 下資源檔 (如 properties、xml)ThisClass.class.getClassLoader().getResourceAsStream("file.name")InputStream所有 (含 JAR 內)
取得資源檔 URL (可轉 File)ThisClass.class.getClassLoader().getResource("file.name")URL所有
Web 專案實體部署路徑 (ServletContext)servletContext.getRealPath("/")String僅 Web 容器

二、完整實戰範例 (JUnit 測試)

package com.example.path;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Properties;
import org.junit.Test;

public class PathDemoTest {

    /** 1. 取得類別編譯輸出目錄 (target/classes/.../com/example/path) */
    @Test
    public void getClassOutputDir() {
        File f = new File(this.getClass().getResource("").getPath());
        System.out.println("類別目錄: " + f.getAbsolutePath());
        // 輸出範例: /project/target/test-classes/com/example/path
    }

    /** 2. 取得 Classpath 根目錄 (target/classes 或 target/test-classes) */
    @Test
    public void getClasspathRoot() {
        File f = new File(this.getClass().getResource("/").getPath());
        System.out.println("Classpath 根目錄: " + f.getAbsolutePath());
        // 輸出範例: /project/target/test-classes
    }

    /** 3. 取得專案根目錄 (Maven 專案根目錄) - 兩種等效寫法 */
    @Test
    public void getProjectRoot() throws IOException {
        File f = new File("");
        String canonical = f.getCanonicalPath();
        String userDir = System.getProperty("user.dir");
        System.out.println("File canonical: " + canonical);
        System.out.println("user.dir: " + userDir);
        // 兩者通常相同: /project
    }

    /** 4. 讀取 src/main/resources 下的資源檔 (推薦用 InputStream) */
    @Test
    public void readResourceFile() {
        // 讀取 jdbc.properties
        try (InputStream is = this.getClass().getClassLoader().getResourceAsStream("jdbc.properties")) {
            Properties props = new Properties();
            props.load(is);
            System.out.println("driver: " + props.getProperty("jdbc.driverClassName"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /** 5. 取得其他 package 下的資源檔 URL */
    @Test
    public void getOtherPackageResource() {
        // 讀取同層級 test2.txt
        URL url = this.getClass().getClassLoader().getResource("test2.txt");
        System.out.println("資源 URL: " + url);
        // file:/project/target/classes/test2.txt
    }

    /** 6. URL 轉 File 並讀取內容 (注意: JAR 內資源無法轉 File) */
    @Test
    public void urlToFile() throws Exception {
        URL url = this.getClass().getClassLoader().getResource("test2.txt");
        if (url != null && "file".equals(url.getProtocol())) {
            File file = new File(url.toURI()); // 使用 toURI() 避免空格編碼問題
            System.out.println("檔案絕對路徑: " + file.getAbsolutePath());
        }
    }
}

三、關鍵重點與避坑指南

1. getResource("") vs getResource("/")

  • getResource(""):相對路徑,**目前類別所在套件目錄**。
  • getResource("/"):絕對路徑,**Classpath 根目錄**。
  • 在 JAR 檔內執行時,回傳的是 jar:file:/path/to.jar!/com/example/ 格式 URL,無法直接轉 File。

2. 必須使用 ClassLoader 讀取資源檔

// ✅ 正確: 委派給系統類別載入器,可跨模組、JAR 讀取
InputStream is = this.getClass().getClassLoader().getResourceAsStream("config.properties");

// ❌ 錯誤: 僅搜尋目前類別所在套件路徑
InputStream is = this.getClass().getResourceAsStream("config.properties");

3. URL 路徑含空格/中文需解碼

// ❌ 直接 getPath() 會保留 %20 等編碼
String path = url.getPath(); 

// ✅ 使用 toURI() 再轉 File,自動處理編碼
File file = new File(url.toURI());

4. Spring 框架中的資源載入 (延伸)

@Autowired
private ResourceLoader resourceLoader;

// 讀取 classpath:config.yml
Resource resource = resourceLoader.getResource("classpath:config.yml");
try (InputStream is = resource.getInputStream()) {
    // 處理流
}

5. Web 專案取得實體部署路徑

@Controller
public class MyController {
    @Autowired
    private ServletContext servletContext;
    
    public void printWebRoot() {
        // 僅適用於解壓縮部署 (exploded war),壓縮 WAR 回傳 null
        String realPath = servletContext.getRealPath("/");
        System.out.println("Web 根目錄: " + realPath);
    }
}

四、環境差異總結表

環境user.dirClasspath 根目錄資源檔讀取
IDE 執行 (IntelliJ/Eclipse)專案根目錄target/classes✅ InputStream 正常
Maven 測試專案根目錄target/test-classes✅ InputStream 正常
打包 JAR 執行JAR 所在目錄JAR 內部根目錄✅ InputStream 正常 (不可轉 File)
Spring Boot 執行啟動命令目錄BOOT-INF/classes✅ ResourceLoader 建議

結語

掌握「Classpath 資源流讀取」與「專案工作目錄」的差異,是 Java 開發者處理配置檔、模板、靜態資源的核心功力。**原則:唯讀資源統一用 getResourceAsStream();需寫入或掃描目錄才用 File 操作專案目錄。**

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved