user5473961
user5473961

Reputation:

How to retrieve working directory of running process in Java?

Original post the one that most people were answering

Here is the code I have already tried doing this with

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

This does not work, once it finishes it comes out with the same working directory.

Any help would be greatly appreciated, this would be a very useful think to know.

To be more specific, I am looking to find the working directory of a dynamically created process in Java, such as in the snippet above. This is important because such as the predefined command above, working directories can change sometimes, I would like to save any changes into memory for later use.

I found a way to do this, and it seems to work problem free

Here is how I am handling the incoming working directory

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

Here is the method of ignoring issues with the path (by not using it)

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

Now here is how I am starting the process for Windows or 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;

Finally here is the loop that manages the process and the working directory

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

Here is the output from the command receiving website

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

Upvotes: 6

Views: 4103

Answers (7)

Bogdan Moisuc
Bogdan Moisuc

Reputation: 1

Your question is unclear a bit, but if you're trying to find the current directory from WITHIN the current process, just do

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

Upvotes: 0

WesternGun
WesternGun

Reputation: 12787

It cannot be achieved in Java by ProcessBuilder's directory() method because it sets the working directory of a process, not where the binary is. You have to do it in another level.

If you are working with GNU/Linux, whereis and update-alternative are your best bet. In Windows, you have where. Now, it comes to the usage of commands in different OS, and the parsing of the outputs. It may be hard.

Some pseudo code to begin with:

  1. execute whereis plus the command as parameter, with ProcessBuilder
  2. try to parse the output. You may deal with multiple line output.

Or,

  1. execute update-alternatives plus the command as parameter, with ProcessBuilder
  2. try to parse the output. There may be several alternatives for one command, such as for java, you may have some different JDKs installed.
  3. Or, list all links in /var/libs/alternatives and find what you want, maybe with pipe. You can see here:

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

But, I still doubt why you are doing this. So, if you can clarify the original requirements, it would help a lot. It's for avoiding X-Y problem.

Upvotes: 1

cruck
cruck

Reputation: 5

Use this to get the URL of your current file directory:

URL url = ClassLoader.getSystemResource(FileName);

It works anywhere. Not just your PC, even in cloud.

It returns an URL(java.net) type. For ClassLoader, you don't need to import anything.

In the FileName, use any filename you want to get the path for.

Upvotes: 0

abhishek sahu
abhishek sahu

Reputation: 648

use the below code

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

Upvotes: -1

Sash
Sash

Reputation: 11

What you can do is to use handle from sysinternals for windows

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

or

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

and find a folder that was last used by that process.

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

and to start you process and get PID use wmic process call create "cmd"

Upvotes: 0

Gray
Gray

Reputation: 116908

I am looking to find the working directory of a dynamically created process in Java,

You can certainly lookup the working directory of the current Java process by looking at the value of the user.dir system property:

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

But finding out the working directory of another process is not possible unless you are using special OS calls. On Linux, if you know the pid then you can look at /proc/[pid]/cwd but there is no easy equivalent in OSX or Windows that I know about.

This does not work, once it finishes it comes out with the same working directory.

Yeah, you are not able to issue a command to change the working directory because once the cmd exits, the working directory will be reset.

According to this page, you can set the working directory by assigning the user.dir system property:

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

However this may be OS dependent and doesn't work on my OSX box. For example, the following code creates the x1 and x2 files in the same directory:

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

This answer says that there is no reliable way to do this in Java. I've always taken the opinion that you can't change the working directory and that you should be specific with new File(parent, filename) to show where files live, etc..

Upvotes: 2

Wasi Ahmad
Wasi Ahmad

Reputation: 37741

Are you looking for something like this?

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

It outputs:

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

Upvotes: 3

Related Questions