【问题标题】:How to retrieve working directory of running process in Java?如何在 Java 中检索正在运行的进程的工作目录?
【发布时间】:2017-03-04 16:45:25
【问题描述】:

原始帖子大多数人都在回答的帖子

这是我已经尝试过的代码

String workingDirectory = "/home";
String command = "cd ../";

ProcessBuilder pb = new ProcessBuilder(new String[] { "cmd", "/c", command });
pb.directory(new File(workingDirectory));
pb.redirectErrorStream(true);
Process process = pb.start();

// Some time later once the process has been closed
workingDirectory = pb.directory().getAbsolutePath();
System.out.println("Path: " + workingDirectory);

这不起作用,一旦完成它就会出现相同的 工作目录。

任何帮助将不胜感激,这将非常有用 想想就知道了。

更具体地说,我正在寻找一个工作目录 Java中动态创建的进程,比如上面的sn -p。 这很重要,因为例如上面的预定义命令, 工作目录有时会改变,我想保存任何 更改为内存供以后使用。

我找到了一种方法,它似乎没有问题

这是我处理传入工作目录的方式

public int osType = 1; // This is for Windows (0 is for Linux)

public boolean isValidPath(String path) {
    try {
        Paths.get(new File(path).getAbsolutePath());
    } catch (InvalidPathException | NullPointerException ex) {
        return false;
    }
    return true;
}

public String tracePath(String path) {
    try {
        if (!path.contains("%%") && !isValidPath(path)) return null;
        if (path.contains("%%")) path = path.substring(path.indexOf("%%"));
        int lastIndex = -1;
        char filesystemSlash = ' ';
        if (osType == 0)
            filesystemSlash = '/';
        if (osType == 1)
            filesystemSlash = '\\';
        if (osType == 0)
            path = path.substring(path.indexOf(filesystemSlash));
        if (osType == 1)
            path = path.substring(path.indexOf(filesystemSlash) - 2);
        String tmp = path;
        boolean broken = true;
        while (!isValidPath(tmp)) {
            int index = tmp.lastIndexOf(filesystemSlash);
            if (lastIndex == index) {
                broken = false;
                break;
            }
            tmp = tmp.substring(0, index);
            lastIndex = index;
        }
        if (broken && lastIndex != -1) {
            tmp = path.substring(0, lastIndex);
        }
        return tmp;
    } catch (StringIndexOutOfBoundsException ex) {
        return null;
    }
}

这是忽略路径问题的方法(不使用它)

public boolean setDirectory(ProcessBuilder pb, String path) {
    try {
        pb.directory(new File(new File(path).getAbsolutePath()));
        return true;
    } catch (Exception ex) {
        return false;
    }
}

现在这是我在 Windows 或 Linux 上启动该过程的方式

File file = null;
        if (osType == 1) {
            ProcessBuilder pb = new ProcessBuilder(new String[] { "cmd", "/c", command + " & echo %% & cd" });
            pb.redirectErrorStream(true);
            if (!workingDirectory.equals(""))
                setDirectory(pb, workingDirectory);
            process = pb.start();
        } else if (osType == 0) {
            file = new File("script.sh");
            FileWriter writer = new FileWriter(file, false);
            writer.append(command + " && echo %% && pwd");
            writer.flush();
            writer.close();
            ProcessBuilder pb = new ProcessBuilder(new String[] { "bash", System.getProperty("user.dir") + "/script.sh" });
            pb.redirectErrorStream(true);
            if (!workingDirectory.equals(""))
                setDirectory(pb, workingDirectory);
            process = pb.start();
        } else
            return;

最后是管理进程和工作目录的循环

while (process.isAlive() || process.getInputStream().available() > 0) {
            byte[] returnBytes = new byte[1024];
            process.getInputStream().read(returnBytes);
            char[] arr = new String(returnBytes).trim().toCharArray();
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < arr.length; i++) {
                char c = arr[i];
                if (Character.isDefined(c))
                    sb.append(c);
            }
            String response = sb.toString();
            if (!response.equals("")) {
                String path = tracePath(response.trim().replace("\n", "").replace("\r", ""));
                if (path != null && osType == 1) {
                    if (Paths.get(path).toFile().exists())
                        workingDirectory = path;
                } else if (path != null && osType == 0) {
                    if (Paths.get(path).toFile().exists())
                        workingDirectory = path;
                }
                client.sendMessage(response + '\r' + '\n');
            }
        }
if (file != null) file.delete();

这是命令接收网站的输出

Connecting..
Connected.
Success. You have been connected -> Speentie

bash -c pwd
/root/hardsceneServer/remoteServer

%%
/root/hardsceneServer/remoteServer

bash -c cd ..

%%
/root/hardsceneServer

bash -c pwd
/root/hardsceneServer

%%
/root/hardsceneServer

bash -c dir
ircServer  nohup.out  remoteServer  start.sh  start1.sh  start2.sh

%%
/root/hardsceneServer

bash -c cd ircServer

%%
/root/hardsceneServer/ircServer

bash -c dir
HardScene.jar         hardscene_banned.properties  start.sh
hardscene.properties  nohup.out

%%
/root/hardsceneServer/ircServer

【问题讨论】:

  • 这里的命令是什么?
  • 如果你问如何检索另一个进程的工作目录,那是不可能的。
  • Linux 能做到的,怎么可能做不到呢?我以为Java也可以与机器接口?必须有一种方法,即使它非常复杂。
  • 您在寻找什么工作目录? jvm使用的那个?
  • 您到底想做什么,为什么?了解这一点可能有助于我们提出更好的解决方案

标签: java process


【解决方案1】:

你在寻找这样的东西吗?

System.out.println("Current working directory: " + System.getProperty("user.dir"));
System.out.println("Changing working directory...");
// changing the current working directory
System.setProperty("user.dir", System.getProperty("user.dir") + "/test/");

// print the new working directory path
System.out.println("Current working directory: " + System.getProperty("user.dir"));

// create a new file in the current working directory
File file = new File(System.getProperty("user.dir"), "test.txt");

if (file.createNewFile()) {
    System.out.println("File is created at " + file.getCanonicalPath());
} else {
    System.out.println("File already exists.");
}

它输出:

Current working directory: /Users/Wasi/NetBeansProjects/TestProject
Changing working directory...
Current working directory: /Users/Wasi/NetBeansProjects/TestProject/test/
File is created at /Users/Wasi/NetBeansProjects/TestProject/test/test.txt

【讨论】:

  • 不是真的,你几乎明白了,你会看到当人们在命令窗口中执行一些“cd ../”时,它会为那个命令执行它,但它不会保存那个新目录到 Java 中的内存中,因为它当然存储在一个全新的进程中。所以我需要的只是某种方式来传入一个进程并获取该进程的工作目录,以便以后可以重用。
  • @SkorrloreGaming 我知道了。但是你为什么不使用System.getProperty("user.dir")?是否只想为某个进程保存当前工作目录?
  • 我只想要动态进程的工作目录,别无其他
【解决方案2】:

我正在寻找在 Java 中动态创建的进程的工作目录,

您当然可以通过查看user.dir系统属性的值来查找当前Java进程的工作目录:

String cwd = System.getProperty("user.dir");

但是,除非您使用特殊的操作系统调用,否则无法找出 另一个 进程的工作目录。在 Linux 上,如果您知道 pid,那么您可以查看 /proc/[pid]/cwd,但我所知道的 OSX 或 Windows 中没有简单的等价物。

这不起作用,一旦完成它就会出现相同的工作目录。

是的,您无法发出更改工作目录的命令,因为一旦 cmd 退出,工作目录将被重置。

根据this page,可以通过分配user.dir系统属性来设置工作目录:

System.setProperty("user.dir", "/tmp");

但是,这可能取决于操作系统,并且不适用于我的 OSX 机器。例如,以下代码在同一目录下创建x1x2 文件:

new File("x1").createNewFile();
// this doesn't seem to do anything
System.setProperty("user.dir", "/tmp");
new File("x2").createNewFile();

This answer 表示在 Java 中没有可靠的方法可以做到这一点。我一直认为您不能更改工作目录,并且您应该使用new File(parent, filename) 来显示文件所在的位置等。

【讨论】:

    【解决方案3】:

    ProcessBuilderdirectory() 方法在 Java 中无法实现,因为它设置的是进程的工作目录,而不是二进制文件所在的位置。你必须在另一个层次上做。

    如果您使用 GNU/Linux,whereisupdate-alternative 是您的最佳选择。在 Windows 中,您有 where。现在,涉及到不同操作系统中命令的使用以及输出的解析。可能很难。

    一些伪代码开头:

    1. 执行whereis加上命令作为参数,ProcessBuilder
    2. 尝试解析输出。您可以处理多行输出。

    或者,

    1. 执行update-alternatives加上命令作为参数,ProcessBuilder
    2. 尝试解析输出。一个命令可能有多种替代方法,例如 java,您可能安装了一些不同的 JDK。
    3. 或者,列出/var/libs/alternatives 中的所有链接并找到你想要的,也许用管道。你可以在这里看到:

    https://serverfault.com/questions/484896/is-there-a-way-to-list-all-configurable-alternatives-symlinks-for-similar-com

    但是,我仍然怀疑你为什么要这样做。所以,如果你能澄清最初的要求,那将有很大帮助。这是为了避免X-Y problem

    【讨论】:

    • +1 这对 Linux 用户很有用,但在测试中这并没有按预期工作。我正在为该项目寻找 Windows 和 Linux 解决方案,尽管这不是一个。不过,值得庆幸的是,我在发布时自己找到了解决方案。
    • 那么,你的解决方案到底是什么?我很感兴趣。
    • 我发布了我用来编辑问题的最新代码。
    【解决方案4】:

    您可以做的是使用来自 sysinternals 的句柄用于 windows

    https://technet.microsoft.com/en-us/sysinternals/bb896655.aspx

    ls -l /proc/[PID]/fd 或 pfiles [PID] for linux

    并找到该进程最后一次使用的文件夹。

    String commandToGetOpenFiles="handle... or ls...";
    BufferedReader reader = new BufferedReader(
            new InputStreamReader(Runtime.getRuntime()
                    .exec(commandToGetOpenFiles).getInputStream()));
    

    要启动你的进程并获取 PID,请使用 wmic 进程调用 create "cmd"

    【讨论】:

      【解决方案5】:

      使用它来获取当前文件目录的 URL:

      URL url = ClassLoader.getSystemResource(FileName);
      

      它可以在任何地方使用。不仅是您的 PC,甚至在云中。

      它返回一个 URL(java.net) 类型。对于ClassLoader,你不需要导入任何东西。

      FileName 中,使用您想要获取路径的任何文件名。

      【讨论】:

        【解决方案6】:

        你的问题有点不清楚,但是如果你想从当前进程中找到当前目录,就这样做

        new File("").getAbsoluteFile().getAbsolutePath();
        

        【讨论】:

          【解决方案7】:

          使用下面的代码

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2018-04-25
            • 2016-08-02
            • 2013-09-13
            • 1970-01-01
            • 2011-03-02
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多