java可以運行時修改工作目錄嗎?


首先我們直接來看一個例子:
程序啟動目錄即工作目錄是/Users/qkkcoolmax/work-private/testuserdir/hehe
 public static void main(String[] args) {
        File file = new File("haha/test.log");
        System.out.println(file.getAbsolutePath());
        //Users/qkkcoolmax/work-private/testuserdir/hehe/haha/test.log
        System.out.println(System.setProperty("user.dir", "/Users/qkkcoolmax/work-private/testuserdir"));
        //Users/qkkcoolmax/work-private/testuserdir/hehe
        System.out.println(System.getProperty("user.dir"));
        //Users/qkkcoolmax/work-private/testuserdir
        System.out.println(file.getAbsolutePath());
        //Users/qkkcoolmax/work-private/testuserdir/haha/test.log
        try {
            new FileOutputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
該程序會拋FileNotFoundException異常。這是由於File對象使用了相對路徑創建,雖然我們動態修改了System.proproties中的user.dir即修改了java層面的工作目錄,但並沒有修改到jvm中實際記錄的工作目錄,所以需要創建的文件路徑中hehe/haha目錄並不存在,從而拋異常。其實System.property只是修改了System中的一個靜態map變量。
而getAbsolutePath返回的是修改工作目錄后的文件路徑,這是由於getAbsolutePath中總是會用System.getProperty("user.dir")來和相對路徑拼接,得到absolutePath。
綜上,我們了解到System.setProperty("user.dir",newPath)的方式是無法修改進程實際的工作目錄的,這個值是存放在jvm底層數據結構中。但是有些特殊場景,我們確實希望能動態修改一下工作目錄。譬如一個服務端進程需要處理不同目錄下的文件,歷史代碼或者框架中使用了一些相對路徑,我們難以替換成絕對路徑時,動態修改工作目錄就成了唯一實現目標的途徑。
 
所以,java是否可以動態修改工作目錄呢?  先說結論,是可以的!
首先,java語言層面並沒有提供這樣的接口。
其次,我們知道在c語言中,可以很方便的調用chdir系統調用來切換當前進程的工作目錄。那么只要java能調用到jvm中鏈進來的libc中的chdir不就好了么。
java調c有幾種方式呢?有一定經驗的讀者可能馬上會想到JNI。實際上,我們可以采用更好的方式即JNA。JNA(Java Native Access )提供一組Java工具類用於在運行期間動態訪問系統本地庫(native library:如Window的dll)而不需要編寫任何Native/JNI代碼。
簡單來說,JNA可以讓java代碼直接調用c代碼(包括jvm里面的代碼),使用方式相比jni更加簡單方便。
對JNA的介紹網上資料還蠻豐富的,感興趣的讀者可以自行搜索研究。這里我們直接使用了jnr-posixz( https://github.com/jnr/jnr-posixz)。該庫已經對不同平台的JNA調用實現了良好的封裝,避免我們使用原生的JNA時處理各種跨平台的邏輯。
 
引入依賴
<dependency>
  <groupId>com.github.jnr</groupId>
  <artifactId>jnr-posix</artifactId>
  <version>3.0.47</version>
</dependency>  
 
使用示例
public class Main {

    private static POSIX posix;

    public static void main(String[] args) {
        posix = POSIXFactory.getPOSIX(new DummyPOSIXHandler(), true);
        File file = new File("haha/test.log");
        System.out.println(file.getAbsolutePath());
        //Users/qkkcoolmax/work-private/testuserdir/hehe/haha/test.log
        System.out.println(System.setProperty("user.dir", "/Users/qkkcoolmax/work-private/testuserdir"));
        posix.chdir(System.getProperty("user.dir"));
        //Users/qkkcoolmax/work-private/testuserdir/hehe
        System.out.println(System.getProperty("user.dir"));
        //Users/qkkcoolmax/work-private/testuserdir
        System.out.println(file.getAbsolutePath());
        //Users/qkkcoolmax/work-private/testuserdir/haha/test.log
        try {
            new FileOutputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

run起來,能夠成功創建出 /Users/qkkcoolmax/work-private/testuserdir/haha/test.log文件,無任何異常。

好了,動態修改java工作目錄達成,請自行取用。

 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM