180

如何从 Java 程序中更改当前工作目录?我能找到的关于这个问题的所有内容都声称你根本做不到,但我不敢相信情况确实如此。

我有一段代码使用硬编码的相对文件路径从通常启动的目录中打开文件,我只想能够在不同的 Java 程序中使用该代码,而不必从内部启动它一个特定的目录。似乎您应该可以调用System.setProperty( "user.dir", "/path/to/dir" ),但据我所知,调用该行只是默默地失败并且什么都不做。

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

4

14 回答 14

154

在纯 Java 中没有可靠的方法来做到这一点。通过或设置user.dir属性似乎确实会影响 的后续创建,但不会影响。System.setProperty()java -Duser.dir=...FilesFileOutputStreams

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

另一种方法是设置一个脚本以从不同的目录运行 Java,或者使用 JNI 本机代码,如下所示

相关的 Sun 错误已于 2008 年关闭,因为“不会修复”。

于 2009-05-08T14:59:28.917 回答
42

如果您使用ProcessBuilder运行您的遗留程序,您将能够指定它的工作目录

于 2009-05-08T15:04:03.977 回答
30

一种方法可以使用系统属性“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");
    }
}
于 2012-12-20T23:00:52.430 回答
21

可以使用 JNA/JNI 调用 libc 来更改 PWD。JRuby 家伙有一个方便的 java 库,用于进行 POSIX 调用,称为jnr-posix。这是maven信息

于 2011-11-20T20:45:07.487 回答
17

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

请参阅Runtime.exec javadocs

具体来说,

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

dir运行子进程的工作目录在哪里

于 2013-02-06T15:20:56.213 回答
11

如果我理解正确,Java 程序从当前环境变量的副本开始。任何更改System.setProperty(String, String)都是修改副本,而不是原始环境变量。并不是说这为 Sun 为什么选择这种行为提供了一个彻底的理由,但也许它揭示了一点点......

于 2009-05-08T14:58:35.470 回答
5

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

File f = new File ( System.getProperty("someprop"), myFilename)
于 2009-05-08T14:59:11.850 回答
4

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

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

于 2009-05-08T15:03:03.290 回答
2

我试图调用

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

它似乎工作。但

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

抛出一个FileNotFoundException虽然

myFile.getAbsolutePath()

显示正确的路径。我读过这个。我认为问题是:

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

解决方案可能是:

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

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

~~~~JcHartmut

于 2014-05-28T20:09:38.513 回答
2

您可以使用

新文件(“相对/路径”).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
于 2017-06-10T07:37:46.117 回答
1

您可以使用 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 );
}
于 2019-12-18T17:51:23.807 回答
0

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

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

于 2009-05-08T15:04:26.923 回答
0

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

于 2012-07-31T15:48:17.243 回答
-1

使用文件系统视图

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);
于 2013-09-11T14:23:20.787 回答