改变 Java 的当前工作目录?

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

我有一段代码,它使用硬编码的相对文件路径从通常启动的目录打开一个文件,我只是希望能够在不同的 Java 程序中使用这段代码,而不必从特定的目录中启动它。看起来你只需要调用 System.setProperty( "user.dir", "/path/to/dir" )就可以了,但是据我所知,调用那条线路就会无声无息地失败,什么也做不了。

如果 Java 不允许你这样做,如果它不允许你使用当前的工作目录,甚至允许你使用相对文件路径打开文件... ..。

251009 次浏览

如果我理解正确的话,Java 程序以当前环境变量的 收到开始。通过 System.setProperty(String, String)进行的任何更改都是修改副本,而不是修改原始环境变量。这并不能完全解释为什么 Sun 会选择这种行为,但是也许能给我们一些启示..。

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

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

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

如果将目录路径与文件路径分开构建,那么 File(String parent, String child)构造函数可以提供帮助,从而使交换更加容易。

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

相关的 OpenJDK bug 在2008年被关闭,因为“不会修复”。

这里更聪明/更容易的做法是更改代码,这样就不必假设文件存在于当前工作目录中(我假设您正在执行类似于 new File("blah.txt")的操作,只需自己构建文件的路径即可。

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

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

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

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

通过使用 JNA/JNI 调用 libc,可以更改 PWD。JRuby 开发人员有一个方便的 java 库,用于进行名为 < strong > jnr-posx 的 POSIX 调用。这是 专家信息

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

提供了一种使用系统属性“ 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");
}
}

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

参见 运行时间,执行 javadocs

具体来说,

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

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

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

我曾试图援引

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

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

JcHartmut

你可以用

新建文件(“相对/路径”) . getAbsoluteFile ()

之后

SetProperty (“ user.dir”,“/some/目录”)

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

将打印

C:\OtherProject\data\data.csv

你可以使用 JNI 或者 JNA 来改变过程的实际工作目录。

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

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

视窗:

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