Java中实现cd命令:运行中更改当前工作目录

原创
2018/08/30 10:36
阅读数 1.2W

因为一些原因,想在Java中模拟部分Shell命令的功能,比如cd、pwd、ls等。

  • 实现pwd很简单,返回System.getProperty("user.dir")即可;
  • 实现ls也不难,用java.nio.file.Files::walk还能实现递归遍历目录;
  • 但在纯Java中实现cd——动态的切换当前工作目录——似乎不是那么容易。

调用System.setProperty("user.dir", "xxx")修改user.dir后,能影响java.io.Filejava.nio.file.Path的后续创建,但不会影响java.io.FileOutputStreamjava.lang.Process等,即写入文件、子进程等当前目录还是进程启动时的目录,不会随系统属性的修改而修改。例如:

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class Application {

    public static void main(String[] args) throws Exception {
        System.out.println(new File(".").getCanonicalPath());

        String home = System.getProperty("user.home");
        String target = home.concat("/Desktop");
        System.setProperty("user.dir", target);
        System.out.println(new File(".").getCanonicalPath());

        try (OutputStream fout = new FileOutputStream("a.txt")) {
            fout.write("hello world".getBytes());
        }
    }
}

在任何非桌面目录下执行上述代码,第一行输出当前路径,第二行输出桌面路径,但a.txt不是创建在桌面。

经过Google,在StackOverflow上找到了一个解决方案:通过jna-posix修改当前目录。不过原始答案中的方法有些过时,经过折腾,找到了在Mac下行之有效的方法。细节如下。

一、pom.xml 引入依赖包

<dependency>
  <groupId>net.java.dev.jna</groupId>
  <artifactId>jna</artifactId>
  <version>4.5.2</version>
</dependency>
<dependency>
  <groupId>com.github.jnr</groupId>
  <artifactId>jnr-posix</artifactId>
  <version>3.0.46</version>
</dependency>

二、实现POSIXHandler

import jnr.constants.platform.Errno;
import jnr.posix.POSIXHandler;

import java.io.File;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.Map;

import static java.util.stream.Collectors.toList;

public class PosixHandler implements POSIXHandler {

    @Override
    public void error(Errno error, String extraData) {
        System.err.printf("%s %s\n", error, extraData);
    }

    @Override
    public void error(Errno error, String methodName, String extraData) {
        System.err.printf("%s %s %s\n", error, methodName, extraData);
    }

    @Override
    public void unimplementedError(String methodName) {
        System.err.printf("%s\n", methodName);
    }

    @Override
    public void warn(WARNING_ID id, String message, Object... data) {
        System.err.printf("%s %s %s\n", id, message, data);
    }

    @Override
    public boolean isVerbose() {
        return false;
    }

    @Override
    public File getCurrentWorkingDirectory() {
        return new File(System.getProperty("user.dir"));
    }

    @Override
    public String[] getEnv() {
        return System.getenv()
                     .entrySet()
                     .stream()
                     .map(Map.Entry::toString)
                     .collect(toList())
                     .toArray(new String[0]);
    }

    @Override
    public InputStream getInputStream() {
        return System.in;
    }

    @Override
    public PrintStream getOutputStream() {
        return System.out;
    }

    @Override
    public int getPID() {
        return 0;
    }

    @Override
    public PrintStream getErrorStream() {
        return System.err;
    }
}

三、利用Posix对象修改当前路径

import jnr.posix.POSIX;
import jnr.posix.POSIXFactory;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class Application {

    public static void main(String[] args) throws Exception {
        System.out.println(new File(".").getCanonicalPath());

        String home = System.getProperty("user.home");
        String target = home.concat("/Desktop");
        System.setProperty("user.dir", target);

        POSIX posix = POSIXFactory.getPOSIX(new PosixHandler(), true);
        posix.chdir(target);
        System.out.println(new File(".").getCanonicalPath());

        try (OutputStream fout = new FileOutputStream("a.txt")) {
            fout.write("hello world".getBytes());
        }
    }
}

此时,再运行该程序,a.txt会被创建在桌面目录下。

展开阅读全文
加载中
点击加入讨论🔥(1) 发布并加入讨论🔥
打赏
1 评论
0 收藏
1
分享
返回顶部
顶部