如何在 Java 中获取当前工作目录?

Posted

技术标签:

【中文标题】如何在 Java 中获取当前工作目录?【英文标题】:How to get the current working directory in Java? 【发布时间】:2011-06-19 18:06:08 【问题描述】:

我想使用 Java 访问我当前的工作目录。

我的代码:

 String currentPath = new java.io.File(".").getCanonicalPath();
 System.out.println("Current dir:" + currentPath);

 String currentDir = System.getProperty("user.dir");
 System.out.println("Current dir using System:" + currentDir);

输出:

Current dir: C:\WINDOWS\system32
Current dir using System: C:\WINDOWS\system32

我的输出不正确,因为 C 盘不是我的当前目录。

如何获取当前目录?

【问题讨论】:

您试图通过访问工作目录来完成什么?可以通过使用类路径来完成吗?例如,如果你需要读取文件系统上的一个文本文件,你可以在类路径上轻松找到它。 怎么样?能详细点吗? 有关访问类路径上的文件的一些信息,请参阅***.com/questions/1464291/… 出于调试目的,工作目录可能有助于了解程序是否似乎无法访问存在的文件。 两种方法(以及下面的方法)看起来都是正确的。如果您将系统目录设为 CWD,那么这可能是由于包装器在启动 Java 之前做了 CD。例如 javapath 可能会这样做。直接将 java.exe 的路径指定到实际的 Java_:home 目录以避免这种情况。 【参考方案1】:

请参阅:Path Operations (The Java™ Tutorials > Essential Classes > Basic I/O)。

使用java.nio.file.Pathjava.nio.file.Paths,您可以执行以下操作来显示Java 认为您当前的路径。这适用于 7 及更高版本,并使用 NIO。

Path currentRelativePath = Paths.get("");
String s = currentRelativePath.toAbsolutePath().toString();
System.out.println("Current absolute path is: " + s);

这个输出:

Current absolute path is: /Users/george/NetBeansProjects/Tutorials

就我而言,这就是我开始上课的地方。

以相对方式构建路径,通过不使用前导分隔符表示您正在构建绝对路径,将使用此相对路径作为起点。

【讨论】:

第一个没有检查,但第二个实际上会获取您的主文件夹。不是当前运行应用程序的工作目录。 请不要混淆用户的主目录(“user.home”,在你的情况下是 /Users/george)和当前工作目录(“user.dir”,它将是来自的目录您为应用程序启动了 JVM,因此可能类似于 /Users/george/workspace/FooBarProject)。 我更喜欢这种方式。当我需要工作目录的父级时,这起作用:Paths.get("").getParent(),它提供null。取而代之的是:Paths.get("").toAbsolutePath().getParent().【参考方案2】:

我最喜欢的方法是从附加到当前运行进程的系统环境变量中获取它。在这种情况下,您的应用程序由 JVM 管理。

String currentDir = System.getenv("PWD");
/*
 /home/$User/Documents/java
*/

查看您可能会发现有用的其他环境变量,例如主目录、操作系统版本........

//Home directory
String HomeDir = System.getEnv("HOME");


//Outputs for unix
/home/$USER

//Device user
String user = System.getEnv("USERNAME");


//Outputs for unix
$USER

这种方法的美妙之处在于,所有路径都将针对所有类型的操作系统平台进行解析

【讨论】:

【参考方案3】:

Java 11 及更新版本

此解决方案比其他解决方案更好,更便携:

Path cwd = Path.of("").toAbsolutePath();

甚至

String cwd = Path.of("").toAbsolutePath().toString();

【讨论】:

这与 comeGetSome 的答案完全相同,实际上是 Java 应该是 Path cwd = Paths.get("").toAbsolutePath(); 最好使用Path.of,因为Paths might get deprecated。此外,Paths.get 只需调用 Path.of @onkarruikar 好点,我会更新答案【参考方案4】:

对于 Java 11,您还可以使用:

var path = Path.of(".").toRealPath();

【讨论】:

【参考方案5】:

尝试这样的事情我知道我迟到了答案但是这个明显的事情发生在 java8 一个新版本中提出这个问题的地方但是..

代码

import java.io.File;

public class Find_this_dir 

    public static void main(String[] args) 

//some sort of a bug in java path is correct but file dose not exist
        File this_dir = new File("");

//but these both commands work too to get current dir        
//      File this_dir_2 = new File(this_dir.getAbsolutePath());
        File this_dir_2 = new File(new File("").getAbsolutePath());

        System.out.println("new File(" + "\"\"" + ")");
        System.out.println(this_dir.getAbsolutePath());
        System.out.println(this_dir.exists());
        System.out.println("");
        System.out.println("new File(" + "new File(" + "\"\"" + ").getAbsolutePath()" + ")");
        System.out.println(this_dir_2.getAbsolutePath());
        System.out.println(this_dir_2.exists());
    

这将起作用并向您显示当前路径,但我现在不知道为什么 java 无法在 new File(""); 中找到当前目录,除了我使用的是 Java8 编译器。 ..

这很好用,我什至测试过new File(new File("").getAbsolutePath());

现在您在 File 对象中有当前目录,因此(示例文件对象为 f),

f.getAbsolutePath() 将为您提供字符串变量类型的路径...

在另一个不是驱动器 C 的目录中测试工作正常

【讨论】:

【参考方案6】:

代码:

public class JavaApplication 
  public static void main(String[] args) 
    System.out.println("Working Directory = " + System.getProperty("user.dir"));
  

这将打印应用程序初始化的当前目录的绝对路径。


说明:

来自documentation:

java.io 包使用当前用户目录解析相对路径名。当前目录表示为系统属性,即user.dir,是调用JVM的目录。

【讨论】:

@ubuntudroid:这就是为什么我特别提到它将打印应用程序初始化的路径。我猜线程启动器在启动 commnad 提示符后直接运行 jar/程序(基本上在 C:\WINDOWS\system32 处)。我希望你明白我的意思。假设您投了反对票,请感谢您至少愿意留下回应。 :) user.dir 将获取启动进程的文件夹的路径。要获取应用程序主文件夹的实际路径,请参阅下面的答案。 我的意思是“所有依赖它查找当前目录的代码都失败了。”。一般而言,并非所有代码。 (我编辑原来的评论太慢了) @SubOptimal 如果用户设置了 -Duser.dir,则可能他想在自定义工作目录中运行它。 @indyaah 事实上这个答案是错误的,系统进程(cwd)的用户工作目录和当前工作目录之间存在细微差别;大多数时候“user.dir”指向(java)进程的cwd;但“user.dir”语义不同,不能用于获取java进程的cwd; btw:java进程docs.oracle.com/javase/tutorial/essential/environment/…还有更多属性可供参考【参考方案7】:

这并不是所要求的,但这里有一个重要说明:在 Windows 机器上运行 Java 时,Oracle 安装程序会将“java.exe”放入 C:\Windows\system32,这就是作为Java 应用程序的启动器(除非 PATH 中有一个 java.exe,并且 Java 应用程序是从命令行运行的)。这就是为什么 File(".") 不断返回 C:\Windows\system32,为什么从 macOS 或 *nix 实现运行示例不断返回与 Windows 不同的结果。

不幸的是,就我在 20 年的 Java 编码中发现的而言,这确实没有普遍正确的答案,除非您想使用 JNI 调用创建自己的本机启动器可执行文件,并从本机获取当前工作目录启动时的启动器代码。其他一切都至少会有一些细微差别,在某些情况下可能会破裂。

【讨论】:

这在很久以前是正确的(当这个 Q 发布时),但微软不鼓励应用程序更改 system32,并且至少从 2015 年开始,Oracle Windows 安装程序将他们的存根放在 \programdata\Oracle\Java\javapath\Program Files [(x86)]\Common Files\Oracle\Java\javapathas MS批准【参考方案8】:

当混乱的时刻冒出来时,这是我的灵丹妙药。(把它称为主要的第一件事)。也许例如 JVM 被 IDE 滑入不同的版本。此静态函数搜索当前进程 PID 并在该 pid 上打开 VisualVM。混乱就停在那里,因为你想要它并且你得到它......

  public static void callJVisualVM() 
    System.out.println("USER:DIR!:" + System.getProperty("user.dir"));
    //next search current jdk/jre
    String jre_root = null;
    String start = "vir";
    try 
        java.lang.management.RuntimeMXBean runtime =
                java.lang.management.ManagementFactory.getRuntimeMXBean();
        String jvmName = runtime.getName();
        System.out.println("JVM Name = " + jvmName);
        long pid = Long.valueOf(jvmName.split("@")[0]);
        System.out.println("JVM PID  = " + pid);
        Runtime thisRun = Runtime.getRuntime();
        jre_root = System.getProperty("java.home");
        System.out.println("jre_root:" + jre_root);
        start = jre_root.concat("\\..\\bin\\jvisualvm.exe " + "--openpid " + pid);
        thisRun.exec(start);
     catch (Exception e) 
        System.getProperties().list(System.out);
        e.printStackTrace();
    

【讨论】:

你应该写一本关于这个问题的书。这 50 行代码还不够。【参考方案9】:

这将为您提供当前工作目录的路径:

Path path = FileSystems.getDefault().getPath(".");

这将为您提供工作目录中名为“Foo.txt”的文件的路径:

Path path = FileSystems.getDefault().getPath("Foo.txt");

编辑: 获取当前目录的绝对路径:

Path path = FileSystems.getDefault().getPath(".").toAbsolutePath();

* 更新 * 获取当前工作目录:

Path path = FileSystems.getDefault().getPath("").toAbsolutePath();

【讨论】:

这只是返回 '.'对我来说。 是的,在许多系统中这将是对工作目录的引用。要获取绝对路径,您可以再添加一个方法调用Path path = FileSystems.getDefault().getPath(".").toAbsolutePath(); 你不需要foo.txt,只需输入一个空字符串即可获取目录 在 Windows (10) 上,这只是给了我一个 Path 对象,指向当前工作目录中名为 . 的文件。使用空字符串,而不是 "." 对我有用。【参考方案10】:

当前工作目录在不同的 Java 实现中定义不同。对于 Java 7 之前的某些版本,没有一致的方法来获取工作目录。您可以通过使用 -D 启动 Java 文件并定义一个变量来保存信息来解决此问题

类似

java -D com.mycompany.workingDir="%0"

这不太对,但你明白了。然后System.getProperty("com.mycompany.workingDir")...

【讨论】:

与问题无关。 它确实对 Java 有意义 - 它是您使用相对路径名打开的文件在磁盘上的相对位置。 是的,它是有含义的。我的话选得有点差。但是你错过了重点——在 Java 7 之前,没有办法知道当前的工作目录,并且不同的实现设置它们......不同......【参考方案11】:

提到它仅在 Windows 中进行检查,但我认为它在其他操作系统上也能完美运行 [Linux,MacOs,Solaris] :)。


我在同一目录中有 2 .jar 文件。我想从一个 .jar 文件中启动另一个位于同一目录中的 .jar 文件。

问题是当你从cmd启动它时,当前目录是system32


警告!

在我做过的所有测试中,以下似乎都运行良好 文件夹名称为 ;][[;'57f2g34g87-8+9-09!2#@!$%^^&()()%&$%^@# 效果很好。 我正在使用ProcessBuilder,如下所示:

?..

//The class from which i called this was the class `Main`
String path = getBasePathForClass(Main.class);
String applicationPath=  new File(path + "application.jar").getAbsolutePath();


System.out.println("Directory Path is : "+applicationPath);

//Your know try catch here
//Mention that sometimes it doesn't work for example with folder `;][[;'57f2g34g87-8+9-09!2#@!$%^^&()` 
ProcessBuilder builder = new ProcessBuilder("java", "-jar", applicationPath);
builder.redirectErrorStream(true);
Process process = builder.start();

//...code

?getBasePathForClass(Class<?> classs):

    /**
     * Returns the absolute path of the current directory in which the given
     * class
     * file is.
     * 
     * @param classs
     * @return The absolute path of the current directory in which the class
     *         file is.
     * @author GOXR3PLUS[*** user] + bachden [*** user]
     */
    public static final String getBasePathForClass(Class<?> classs) 

        // Local variables
        File file;
        String basePath = "";
        boolean failed = false;

        // Let's give a first try
        try 
            file = new File(classs.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());

            if (file.isFile() || file.getPath().endsWith(".jar") || file.getPath().endsWith(".zip")) 
                basePath = file.getParent();
             else 
                basePath = file.getPath();
            
         catch (URISyntaxException ex) 
            failed = true;
            Logger.getLogger(classs.getName()).log(Level.WARNING,
                    "Cannot firgue out base path for class with way (1): ", ex);
        

        // The above failed?
        if (failed) 
            try 
                file = new File(classs.getClassLoader().getResource("").toURI().getPath());
                basePath = file.getAbsolutePath();

                // the below is for testing purposes...
                // starts with File.separator?
                // String l = local.replaceFirst("[" + File.separator +
                // "/\\\\]", "")
             catch (URISyntaxException ex) 
                Logger.getLogger(classs.getName()).log(Level.WARNING,
                        "Cannot firgue out base path for class with way (2): ", ex);
            
        

        // fix to run inside eclipse
        if (basePath.endsWith(File.separator + "lib") || basePath.endsWith(File.separator + "bin")
                || basePath.endsWith("bin" + File.separator) || basePath.endsWith("lib" + File.separator)) 
            basePath = basePath.substring(0, basePath.length() - 4);
        
        // fix to run inside netbeans
        if (basePath.endsWith(File.separator + "build" + File.separator + "classes")) 
            basePath = basePath.substring(0, basePath.length() - 14);
        
        // end fix
        if (!basePath.endsWith(File.separator)) 
            basePath = basePath + File.separator;
        
        return basePath;
    

【讨论】:

这将返回 JAR 文件的位置。不是所要求的。 @EJP .jar文件所在的位置不是java程序的当前工作目录?【参考方案12】:

以下适用于 Java 7 及更高版本(有关文档,请参阅 here)。

import java.nio.file.Paths;

Paths.get(".").toAbsolutePath().normalize().toString();

【讨论】:

这比更便携的import java.io.File; File(".").getAbsolutePath() 好在哪里? 当您说可移植时,您的意思是它可以在 Java 6 及更早版本中运行? Paths.get() 可能被认为更好,因为它可以直接访问更强大的Path 接口。 在这种情况下使用.normalize() 的潜在优势是什么? @OleV.V.来自 Javadoc:(规范化方法Returns a path that is this path with redundant name elements eliminated.【参考方案13】:

是什么让您认为 c:\windows\system32 不是您的当前目录? user.dir 属性明确为“用户的当前工作目录”。

换句话说,除非您从命令行启动 Java,否则 c:\windows\system32 可能是您的 CWD。也就是说,如果您双击启动程序,则 CWD 不太可能是您从中双击的目录。

编辑:这似乎只适用于旧 Windows 和/或 Java 版本。

【讨论】:

这似乎不是真的,至少在我使用 Java 7 的 Windows 7 机器上不是这样。user.dir 始终是我双击 jar 文件的文件夹。【参考方案14】:

使用CodeSource#getLocation()

这在 JAR 文件中也可以正常工作。您可以通过ProtectionDomain#getCodeSource()获得CodeSource,而ProtectionDomain又可以通过Class#getProtectionDomain()获得。

public class Test 
    public static void main(String... args) throws Exception 
        URL location = Test.class.getProtectionDomain().getCodeSource().getLocation();
        System.out.println(location.getFile());
    

【讨论】:

这将返回 JAR 文件的位置。不是所要求的。【参考方案15】:

使用 Windows user.dir 会按预期返回目录,但不是在您以提升的权限启动应用程序时(以管理员身份运行),在这种情况下您会得到 C:\WINDOWS\system32

【讨论】:

【参考方案16】:

Linux 上,当您从 终端 运行 jar 文件时,它们都将返回相同的 String"/home/CurrentUser",不管你的 jar 文件在哪里。这仅取决于您在启动 jar 文件时在终端上使用的当前目录。

Paths.get("").toAbsolutePath().toString();

System.getProperty("user.dir");

如果你的Classmain 会被称为MainClass,那么试试:

MainClass.class.getProtectionDomain().getCodeSource().getLocation().getFile();

这将返回一个带有 jar 文件的绝对路径String

【讨论】:

这不是所要求的。 这个答案不能按字面意思理解。【参考方案17】:

假设您正在尝试在 eclipse 或 netbean 中运行您的项目,或者在命令行中单独运行。我已经写了一个方法来修复它

public static final String getBasePathForClass(Class<?> clazz) 
    File file;
    try 
        String basePath = null;
        file = new File(clazz.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
        if (file.isFile() || file.getPath().endsWith(".jar") || file.getPath().endsWith(".zip")) 
            basePath = file.getParent();
         else 
            basePath = file.getPath();
        
        // fix to run inside eclipse
        if (basePath.endsWith(File.separator + "lib") || basePath.endsWith(File.separator + "bin")
                || basePath.endsWith("bin" + File.separator) || basePath.endsWith("lib" + File.separator)) 
            basePath = basePath.substring(0, basePath.length() - 4);
        
        // fix to run inside netbean
        if (basePath.endsWith(File.separator + "build" + File.separator + "classes")) 
            basePath = basePath.substring(0, basePath.length() - 14);
        
        // end fix
        if (!basePath.endsWith(File.separator)) 
            basePath = basePath + File.separator;
        
        return basePath;
     catch (URISyntaxException e) 
        throw new RuntimeException("Cannot firgue out base path for class: " + clazz.getName());
    

要使用,无论你想获得读取文件的基本路径,你可以将你的锚类传递给上面的方法,结果可能是你需要的东西:D

最好的,

【讨论】:

这将返回 JAR 文件的位置。不是所要求的。 @user207421 是的,我知道这个答案不是问题的真正答案,但大多数时候,每个人都希望获得“jar 所在的目录”而不是“命令行工作目录”。 【参考方案18】:

此处发布的所有答案均不适合我。以下是有效的方法:

java.nio.file.Paths.get(
  getClass().getProtectionDomain().getCodeSource().getLocation().toURI()
);

编辑:我的代码中的最终版本:

URL myURL = getClass().getProtectionDomain().getCodeSource().getLocation();
java.net.URI myURI = null;
try 
    myURI = myURL.toURI();
 catch (URISyntaxException e1) 

return java.nio.file.Paths.get(myURI).toFile().toString()

【讨论】:

这将返回 JAR 文件的位置。不是所要求的。【参考方案19】:

通常,作为文件对象:

File getCwd() 
  return new File("").getAbsoluteFile();

您可能希望拥有像 "D:/a/b/c" 这样的完整限定字符串:

getCwd().getAbsolutePath()

【讨论】:

这在 android 测试中效果很好,因为 Android 不包含 java.nio.file.Files。 在静态上下文中似乎对我不起作用(new File("") throws NullPointerException)..? @nsandersen 您可能使用了错误的文件对象:System.out.println(new java.io.File("").getAbsolutePath());【参考方案20】:

System.getProperty("java.class.path")

【讨论】:

【参考方案21】:

我在 Linux 上使用这两种方法得到相同的结果:

@Test
public void aaa()

    System.err.println(Paths.get("").toAbsolutePath().toString());

    System.err.println(System.getProperty("user.dir"));

Paths.get("") docs

System.getProperty("user.dir") docs

【讨论】:

【参考方案22】:

我希望你想访问包含包的当前目录,即如果你的 Java 程序在c:\myApp\com\foo\src\service\MyTest.java 并且你想打印到c:\myApp\com\foo\src\service 那么你可以试试下面的代码:

String myCurrentDir = System.getProperty("user.dir")
            + File.separator
            + System.getProperty("sun.java.command")
                    .substring(0, System.getProperty("sun.java.command").lastIndexOf("."))
                    .replace(".", File.separator);
    System.out.println(myCurrentDir);

注意:此代码仅在 Windows 中使用 Oracle JRE 进行测试。

【讨论】:

不反对这个答案是有害的。发帖前请三思。你的代码坏了,除非所有这些都是真的: 1. JRE 是 Oracle 的,否则将没有“sun.java.command”系统属性→NPE; 2.操作系统是Windows(使用File.separator代替,或多参数File构造函数); 3. 命令行中指定了类路径, '当前目录包括包'(??) 是:首先指定,b。绝对指定,c。与 CWD 完全匹配(即使 Windows 不区分大小写),并且 d.是 CWD 的后代 解决了第 1 点和第 2 点。但除非我遗漏了什么,否则您仍然依赖于在命令行中指定的类路径(即不在环境变量中),并且对于 '当前目录,包括包'(我承认我不太明白你的意思)是类路径中第一个元素的后代。并且大小写匹配问题仍然存在。如果我的评论没有帮助,我很抱歉;我牺牲了清晰度以保持在评论字符限制内。 @Inversus,它只在某些环境中“完美运行”;你只是碰巧有幸以这样的方式测试它。编写在合法运行时环境中失败的软件并不是一个好的做法,即使您的测试环境集不够广泛,无法包含它们。 @CharlesDuffy 你是对的,这不是一个好习惯。幸运的是,这个解决方案“解决了我的特定问题”并没有导致它“在合法的运行时环境中失败”。事实上,它帮助我解决了这样的失败并编写了更健壮的代码,除了解决我遇到的非常具体的问题(这只是与这个问题/答案有点相关)。我想我很幸运能找到它。【参考方案23】:

这就是我的解决方案

File currentDir = new File("");

【讨论】:

当您使用这样的 File 对象作为另一个 File 的父级时,这会产生副作用:new File(new File(""), "subdir") 将无法按预期工作 要解决这个问题,请改用new File("").getAbsoluteFile() 对于它的价值,我最好用 File(".")。 How To Define a Relative Path in Java 这个页面帮助了我。我还假设在创建相对路径时应该使用/。我错了,不要以/开头。 ../ 也适用于在目录树中向上。 @keshlam 这给了我当前目录中一个名为 . 的文件。【参考方案24】:
this.getClass().getClassLoader().getResource("").getPath()

【讨论】:

当我通过双击从 JAR 文件启动我的应用程序时引发 NPE。 如果应用程序从 JAR 文件或 CLASSPATH 元素运行,则返回 ""。不是所要求的。 @Zizouz212 getClass() 是一种对象方法,因此在静态上下文中仅删除 this 是行不通的。您必须通过 MyClass.class.getClassLoader()..... 明确引用您所在的课程。

以上是关于如何在 Java 中获取当前工作目录?的主要内容,如果未能解决你的问题,请参考以下文章

Java获取程序运行的当前工作目录

如何在 Objective-C 中获取当前工作目录的绝对路径?

如何获取当前工作目录路径 c#?

如何获取 Xcode Playground 的当前工作目录?

java属性 user.dir获取当前工作目录

如何获取 Grails/Tomcat Webapp 的当前工作目录?