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


169

如何在Java程序中更改当前工作目录?我已经找到的关于该问题的所有信息都声称您根本做不到,但我不敢相信确实如此。

我有一段代码可以使用通常从其开始的目录中的硬编码相对文件路径打开文件,而我只想能够从其他Java程序中使用该代码而不必从内部启动特定目录。看来您应该可以拨打System.setProperty( "user.dir", "/path/to/dir" ),但据我所知,仅默默地拨打那条电话就行不通了。

我会理解Java是否不允许您执行此操作,或者是否不是因为Java允许您获取当前工作目录,甚至不允许您使用相对文件路径打开文件...。


1
获取和使用信息与更改信息不同。例如,在Windows上,您可以轻松获取环境变量,但是很难更改它们(以系统范围的方式)。
PhiLho

1
bugs.java.com/bugdatabase/view_bug.do?bug_id=4045688在评估部分中指出:“自那时以来,没有其他客户提出要求或以其他方式识别出……。”截至2018年,我们的客户数量已达到175.000这个问题的看法:-(
Wolfgang Fahl,

Answers:


146

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

File(String parent, String child),如果你从你的文件路径单独建立你的目录路径,用户可以方便地交换构造可以提供帮助。

一种替代方法是设置脚本以从其他目录运行Java,或使用JNI本机代码,如下所示

相关的Sun错误已于2008年关闭,原因是“无法修复”。


12
我认为我没有发现Java和C#之间有一个单一的区别,这让我想到“那些Java家伙肯定知道他们在做什么”
Jake 2012年

2
很难相信Java至少没有某些参数“在此目录中启动...”
rogerdpack 2013年

5
在Java的辩护下(我是一个渴望使用此功能的UNIX专家)...这是一台虚拟机,旨在与操作系统无关。在某些操作系统中,“当前工作目录”惯用语不可用。
Tony K.

4
为了对Java公平起见,他们必须首先这样做,C#的好处是能够从许多领域的错误中学习。
Ryan The Leach 2014年

3
@VolkerSeibt:在进一步研究中,似乎user.dir仅适用于某些类,包括我最初测试过的类。new FileOutputStream("foo.txt").close();即使该程序更改了user.dir,也会在原始工作目录中创建文件。
迈克尔·迈尔斯

37

如果使用ProcessBuilder运行旧程序,则可以指定其工作目录


1
的路线是我走的路线。我可以使用以下命令从其他工作目录运行可执行文件:File WorkingDir = new File(“ C:\\ path \\ to \\ working \\ dir \\”); ProcessBuilder pBuilder =新的ProcessBuilder(“ C:\\ path \\ to \\ working \\ dir \\ executable.exe”); pBuilder.directory(WorkingDir); 进程p = pBuilder.start();
CatsAndCode

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
绝对路径至关重要
HackNone 2013年

5
但这不会更改当前的工作目录。只有的值user.dir。绝对路径变得至关重要的事实证明了这一点。
洛恩侯爵,

18

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

您可以在此处查看其用法示例(Clojure代码,抱歉)。看一下函数chdirToRoot


1
似乎没有现代的jna-posix版本。我分叉并添加了一个:github.com/pbiggar/jnr-posix。我可以确认可以使用此功能更改PWD。
Paul Biggar

是。抱歉,我重构了该文件,却忘记了链接到该文件的答案。固定。
艾伦·罗纳

您可以执行此操作,但是如果您还不更改user.dirsystem属性,则将根据File.getAbsolutePath()解析user.dir,而File中的路径名将针对OS工作目录解析。
莫里2014年

关于原始问题,使用jnr-posix,如何更改Java中的当前工作目录。我必须创建哪个类才能使用chdir方法?我不太了解所提供的Clojure示例。提前致谢。

12

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

请参阅Runtime.exec javadocs

特别,

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

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


1
这似乎是一个比公认的答案更好的答案(它以“在纯Java中没有可靠的方法来做到这一点”开头)。有没有一种方法可以将此请求视为已接受的请求?
约翰

11

如果我理解正确,那么Java程序将从当前环境变量的副本开始。通过System.setProperty(String, String)进行的任何更改都将修改副本,而不是原始环境变量。并不是说这为Sun选择了此行为提供了充分的理由,但也许可以揭示一点点...


2
您似乎混淆了环境变量和属性。前者从OS继承而来,后者可以在命令行上定义-D。但是我同意,在JVM上启动预定义的属性,例如user.dir从OS复制并在以后更改它们没有帮助。
maaartinus 2012年

更改user.dir会影响File.getAbsolutePath()File.getCanonicalPath(),但不会影响操作系统对工作目录的想法,后者决定了在访问文件时如何解析文件路径名。
莫里2014年

5

工作目录是操作系统功能(在进程启动时设置)。您为什么不只传递自己的System属性(-Dsomeprop=/my/path),然后在代码中将其用作File的父级:

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

因为这段代码包含一个硬编码的文件路径,并且可能使用了一个硬编码的构造函数,该构造函数未指定要从其工作的父目录。Atleast,这就是我的处境:)
David Mann

4

此处更聪明/更轻松的事情是更改代码,这样就不必假设当前工作目录中存在该文件,也不必打开文件(我假设您正在执行类似 new File("blah.txt"),只需自己构建文件的路径即可。

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


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


“它创建一个文件对象”-是的。但是它不会在文件系统中创建文件。之后,您忘记使用file.createNewFile()了。
Gangnus

2

您可以使用

新File(“ relative / path”)。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

1
请注意,此行为在Java 11中已更改,请参见bugs.openjdk.java.net/browse/JDK-8202127。他们不建议使用System.setProperty("user.dir", "/some/directory")
马丁

0

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

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


0

如果您在Shell中运行命令,则可以编写“ java -cp”之类的内容,并添加要用“:”分隔的任何目录。如果java在一个目录中找不到任何内容,它将尝试在其他目录中找到它们,是我的工作。


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 );
}

-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);

导入javax.swing.filechooser.FileSystemView;
Borneq 2013年

1
这个答案与问题无关。
亚伦·迪古拉
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.