在Java中更改当前工作目录?

时间:2009-05-08 14:54:05

标签: java working-directory

如何在Java程序中更改当前工作目录?我能找到的关于这个问题的一切声称你根本做不到,但我不相信那是真的。

我有一段代码使用来自通常启动的目录的硬编码相对文件路径打开文件,我只是希望能够在不同的Java程序中使用该代码而无需启动它来自特定目录。看起来你应该只能调用System.setProperty( "user.dir", "/path/to/dir" ),但据我所知,调用该行只是默默地失败并且什么都不做。

我会理解Java是否允许您这样做,如果不是因为它允许您获取当前工作目录,甚至允许您打开文件使用相对文件路径....

14 个答案:

答案 0 :(得分:140)

在纯Java中没有可靠的方法。通过user.dirSystem.setProperty()设置java -Duser.dir=...属性似乎会影响Files的后续创建,但不会影响FileOutputStreams {{1}}。

如果您与文件路径分开构建目录路径,File(String parent, String child)构造函数可以提供帮助,从而可以更轻松地进行交换。

另一种方法是设置脚本以从其他目录运行Java,或使用JNI本机代码as suggested below

The relevant Sun bug于2008年关闭,因为“无法修复”。

答案 1 :(得分:36)

如果您使用ProcessBuilder运行旧版程序,则可以指定其工作directory

答案 2 :(得分:29)

使用系统属性“user.dir”执行此操作的方法。要理解的关键部分是必须调用getAbsoluteFile()(如下所示),否则将根据默认“user.dir”值解析相对路径。

import java.io.*;

public class FileUtils
{
    public static boolean setCurrentDirectory(String directory_name)
    {
        boolean result = false;  // Boolean indicating whether directory was set
        File    directory;       // Desired current working directory

        directory = new File(directory_name).getAbsoluteFile();
        if (directory.exists() || directory.mkdirs())
        {
            result = (System.setProperty("user.dir", directory.getAbsolutePath()) != null);
        }

        return result;
    }

    public static PrintWriter openOutputFile(String file_name)
    {
        PrintWriter output = null;  // File to open for writing

        try
        {
            output = new PrintWriter(new File(file_name).getAbsoluteFile());
        }
        catch (Exception exception) {}

        return output;
    }

    public static void main(String[] args) throws Exception
    {
        FileUtils.openOutputFile("DefaultDirectoryFile.txt");
        FileUtils.setCurrentDirectory("NewCurrentDirectory");
        FileUtils.openOutputFile("CurrentDirectoryFile.txt");
    }
}

答案 3 :(得分:17)

可以使用JNA / JNI来调用libc来更改PWD。 JRuby的人有一个方便的java库,用于调用POSIX调用jna-posix这里是the maven info

你可以看到它的使用示例here(Clojure代码,抱歉)。查看函数chdirToRoot

答案 4 :(得分:11)

如果我理解正确,Java程序将以当前环境变量的 copy 开头。通过System.setProperty(String, String)进行的任何更改都会修改副本,而不是原始环境变量。并不是说这为Sun选择这种行为的原因提供了一个彻底的理由,但也许它有点轻松......

答案 5 :(得分:11)

如前所述,您无法更改JVM的CWD,但如果您要使用Runtime.exec()启动另一个进程,则可以使用重载方法来指定工作目录。这不是真正用于在另一个目录中运行Java程序,但是在许多情况下,当需要启动另一个程序(例如Perl脚本)时,您可以指定该脚本的工作目录,同时保持JVM的工作目录不变。 / p>

请参阅Runtime.exec javadocs

具体地,

public Process exec(String[] cmdarray,String[] envp, File dir) throws IOException

其中dir是在

中运行子进程的工作目录

答案 6 :(得分:5)

工作目录是操作系统功能(在进程启动时设置)。 为什么不直接传递自己的系统属性(-Dsomeprop=/my/path)并在代码中使用它作为文件的父级:

File f = new File ( System.getProperty("someprop"), myFilename)

答案 7 :(得分:4)

这里更聪明/更容易的事情就是改变你的代码,以便假设它存在于当前工作目录中而不是打开文件(假设你正在做类似new File("blah.txt")的事情,那么只需构建你自己的文件路径。

让用户传入基本目录,从配置文件中读取它,如果找不到其他属性,则回退到user.dir等等。但是改进逻辑更容易你的程序,而不是改变环境变量的工作方式。

答案 8 :(得分:2)

我试图调用

String oldDir = System.setProperty("user.dir", currdir.getAbsolutePath());

似乎有效。但是

File myFile = new File("localpath.ext"); InputStream openit = new FileInputStream(myFile);

引发FileNotFoundException

myFile.getAbsolutePath()

显示正确的路径。 我有read this。我认为问题是:

  • Java使用新设置知道当前目录。
  • 但文件处理由操作系统完成。遗憾的是,它不知道新的当前目录。

解决方案可能是:

File myFile = new File(System.getPropety("user.dir"), "localpath.ext");

它创建一个文件Object作为绝对的文件,使用JVM已知的当前目录。但是该代码应该存在于已使用的类中,它需要更改重用代码。

~~~~ JcHartmut

答案 9 :(得分:1)

您可以使用

  

新文件("亲戚/路径")。getAbsoluteFile()

之后

  

System.setProperty(" user.dir"," / some / directory")

System.setProperty("user.dir", "C:/OtherProject");
File file = new File("data/data.csv").getAbsoluteFile();
System.out.println(file.getPath());

将打印

C:\OtherProject\data\data.csv

答案 10 :(得分:0)

此问题的其他可能答案可能取决于您打开文件的原因。这是属性文件还是具有与您的应用程序相关的配置的文件?

如果是这种情况,您可以考虑尝试通过类路径加载器加载文件,这样您就可以加载Java有权访问的任何文件。

答案 11 :(得分:0)

如果你在shell中运行你的命令你可以编写类似“java -cp”的东西,并添加你想要用“:”分隔的任何目录,如果java在一个目录中找不到它会尝试在另一个目录中找到它们目录,这就是我所做的。

答案 12 :(得分:0)

您可以使用JNI或JNA更改进程的实际工作目录。

使用JNI ,您可以使用本机函数来设置目录。 POSIX方法为chdir()。在Windows上,您可以使用SetCurrentDirectory()

使用JNA ,您可以将本机函数包装在Java绑定器中。

对于Windows:

private static interface MyKernel32 extends Library {
    public MyKernel32 INSTANCE = (MyKernel32) Native.loadLibrary("Kernel32", MyKernel32.class);

    /** BOOL SetCurrentDirectory( LPCTSTR lpPathName ); */
    int SetCurrentDirectoryW(char[] pathName);
}

对于POSIX系统:

private interface MyCLibrary extends Library {
    MyCLibrary INSTANCE = (MyCLibrary) Native.loadLibrary("c", MyCLibrary.class);

    /** int chdir(const char *path); */
    int chdir( String path );
}

答案 13 :(得分:-1)

使用FileSystemView

private FileSystemView fileSystemView;
fileSystemView = FileSystemView.getFileSystemView();
currentDirectory = new File(".");
//listing currentDirectory
File[] filesAndDirs = fileSystemView.getFiles(currentDirectory, false);
fileList = new ArrayList<File>();
dirList = new ArrayList<File>();
for (File file : filesAndDirs) {
if (file.isDirectory())
    dirList.add(file);
else
    fileList.add(file);
}
Collections.sort(dirList);
if (!fileSystemView.isFileSystemRoot(currentDirectory))
    dirList.add(0, new File(".."));
Collections.sort(fileList);
//change
currentDirectory = fileSystemView.getParentDirectory(currentDirectory);