如何在Java 8+;中正确实现更改目录支持;?

如何在Java 8+;中正确实现更改目录支持;?,java,Java,我正在编写一个脚本解释器/shell,我需要更改目录支持才能有效地完成这项工作 现在,我使用一个文件对象引用作为当前目录,并使用该文件对象解析所有相对路径。这是可行的,但问题是解释器使用的每个文件引用都有一个绝对路径。这在获取相对URI或发生错误时效果不佳,错误消息不会反映提供给脚本引擎的路径,这将使脚本调试非常“非直观”(正确的错误消息是关于错误输入的逐字逐句) 如果无法更改当前目录,Java的文件对象基本上已经过时。当然,如果java允许我在文件对象上指定我当前的目录,这不会是一个问题,但是

我正在编写一个脚本解释器/shell,我需要更改目录支持才能有效地完成这项工作

现在,我使用一个文件对象引用作为当前目录,并使用该文件对象解析所有相对路径。这是可行的,但问题是解释器使用的每个文件引用都有一个绝对路径。这在获取相对URI或发生错误时效果不佳,错误消息不会反映提供给脚本引擎的路径,这将使脚本调试非常“非直观”(正确的错误消息是关于错误输入的逐字逐句)

如果无法更改当前目录,Java的文件对象基本上已经过时。当然,如果java允许我在文件对象上指定我当前的目录,这不会是一个问题,但是我不知道有什么方法可以做到这一点,除了用这种特性支持扩展文件类

为了进一步加剧这种缺乏正确特性支持的逻辑谬误,我基本上面临着使用process builder运行流程的相同问题

我知道我已经“完成了”,但对我的项目来说,“正确完成”是非常重要的,这意味着透明

我已经看到了堆栈溢出的答案,上面说:修改系统属性:
user.dir
,但这完全是错误的,不适用于我的JVM

我根本不在乎JVM规范在这种情况下说我应该做什么或不应该做什么(因为我不相信逻辑谬误),我只想以跨平台兼容的方式更改当前目录。每个主要的操作系统都支持这个特性,但是Java不支持?(辣根!)

如何在Java 8+中正确实现更改目录支持?

经过一番挖掘,我发现了。显然,当年的JDK团队无法理解当前目录的概念(这与更改其他进程和线程的当前目录无关)

出于所有意图和目的,
更改目录用于当前正在执行的线程(进程)以及该线程或其子线程中的所有未来相关文件系统访问操作(引用此)。某些操作系统甚至所有的规范可能对其影响有不同的概念,但从最终用户的角度来看,change directory就是这样做的。完全系统兼容并不是更改目录的用例,但如何影响未来的每个文件操作是用例,因此有了“更改”一词

Java基本上是一个系统仿真层,所有文件系统IO操作都绑定在该层内。在Java决定忽略其他相关的系统标准之前,忽略提供变更目录模拟过去是,而且永远是Java预见中最大的失败

我对编写仿真层并不陌生。这与底层实现无关。这是unix哲学的核心原则。它是关于提供完成工作的能力。也就是说,从开发的JDK方面实现JDK更改目录特性并不是不可能或困难的

如果你看我的答案,它就像提供一个线程安全的静态变量一样简单,在相对路径的情况下,所有文件操作都将访问该变量<代码>优步失败

所以这里是我的“示例”,它提供了有限的支持。我不接受这个答案,因为它不能解决所有问题。例如,流IO。但是对于只需要
java.io.File
支持以正确的错误输出更改当前目录的轻量级项目,这应该可以做到

我说应该这样做,因为我还没有测试过它。此代码不完整。我从未在java中使用过文件过滤器,所以我不知道如何修补这些入口点。这些方法被标记为已弃用,如果调用,将引发不支持的操作异常

使用此工具,您可以设置并获取当前目录值,并且所有文件方法都将使用您提供的路径,除非有磁盘访问;在这种情况下,它将返回到实际文件的路径。如果引发异常,代码将尝试(再次,未测试)使用您提供的路径更正错误消息

毫无疑问,爪哇的人真的把这件事搞砸了;基本上,您必须修补/破解/模拟整个Java IO平台,以便支持更改目录。我的朋友们是我们所说的严重的疏忽;一个临时的编码错误。在这个地球上,没有一个程序员值得他这么做,他认为废除一个比他或她更老的计算编码标准是一个明智的想法,而这个标准从一开始就没有问题

磁盘操作系统,不改变目录?你很幸运没有为我工作。你会在邮件中收到你的解雇文件。因为如果你带着这样的“修复程序”(无更改目录支持)走进我的办公室,我会勒死你的

import java.io.*;
import java.net.URI;
import java.nio.file.Path;

public class HSFile extends java.io.File {

  /*
    For this class to work as intended, we need to intervene in any
    method which transposes the file's name, accesses the disk,
    or throws exceptions.
  */

  private final File realFile;
  private final String realDirectory;

  public static String getCurrentDirectory() {
    return currentDirectory.getPath();
  }

  public static void setCurrentDirectory(String currentDirectory) throws
    FileNotFoundException {
    File target = new File(currentDirectory);
    if (! target.exists() )
      throw new FileNotFoundException("target directory: `"+target+"'; does not exist");
    if (! target.isDirectory())
      throw new UnsupportedOperationException("target directory: `"+target+"'; is not a directory");
    HSFile.currentDirectory = target;
  }

  /**
   * The global current directory property
   */
  private static java.io.File currentDirectory =
    new File(java.lang.System.getProperty("user.dir"));

  public File getRealFile() {
    if (realFile != null) return realFile;
    if (! isAbsolute()) return new File(getCurrentDirectory(), getPath());
    return new File(this.getPath());
  }

  public String getRealPath() { return realFile.getPath(); }

  public HSFile(String s) {
    super(s);
    realFile = getRealFile();
    if (! isAbsolute()) {
      realDirectory = getCurrentDirectory() + File.separator;
    } else realDirectory = realFile.getParent() + File.separator;
  }

  public HSFile(String s, String s1) {
    super(s, s1);
    realFile = getRealFile();
    realDirectory = s + File.separator;
  }

  public HSFile(File file, String s) {
    super(file, s);
    realFile = getRealFile();
    realDirectory = file.getPath() + File.separator;
  }

  public HSFile(URI uri) {
    super(uri);
    realFile = getRealFile();
    if (! isAbsolute()) {
      realDirectory = getCurrentDirectory() + File.separator;
    } else realDirectory = realFile.getParent() + File.separator;
  }

  @Override
  public boolean canRead() {
    return realFile.canRead();
  }

  @Override
  public boolean canWrite() {
    return realFile.canWrite();
  }

  @Override
  public boolean exists() {return realFile.exists();}

  @Override
  public boolean isDirectory() {return realFile.isDirectory();}

  @Override
  public boolean isFile() {return realFile.isFile();}

  @Override
  public boolean isHidden() {return realFile.isHidden();}

  @Override
  public long lastModified() {return realFile.lastModified();}

  @Override
  public long length() {return realFile.length();}

  @Override
  public boolean createNewFile() throws IOException {
    return realFile.createNewFile();
  }

  @Override
  public boolean delete() {return realFile.delete();}

  @Override
  public void deleteOnExit() {realFile.deleteOnExit();}

  @Override
  public boolean mkdir() {return realFile.mkdir();}

  @Override
  public boolean mkdirs() {return realFile.mkdirs();}

  @Override
  public boolean setLastModified(long l) {return realFile.setLastModified(l);}

  @Override
  public boolean setWritable(boolean b, boolean b1) {
    return realFile.setWritable(b, b1);
  }

  @Override
  public boolean setWritable(boolean b) {return realFile.setWritable(b);}

  @Override
  public boolean setReadable(boolean b, boolean b1) {
    return realFile.setReadable(b, b1);
  }

  @Override
  public boolean setReadable(boolean b) {return realFile.setReadable(b);}

  @Override
  public boolean setExecutable(boolean b, boolean b1) {
    return realFile.setExecutable(b, b1);
  }

  @Override
  public boolean setExecutable(boolean b) {return realFile.setExecutable(b);}

  @Override
  public boolean canExecute() {
    return realFile.canExecute();
  }

  @Override
  public long getTotalSpace() {return realFile.getTotalSpace();}

  @Override
  public long getFreeSpace() {return realFile.getFreeSpace();}

  @Override
  public long getUsableSpace() {return realFile.getUsableSpace();}

  @Override
  public String getAbsolutePath() {
    return realFile.getAbsolutePath();
  }

  @Override
  public HSFile getAbsoluteFile() {
    return new HSFile(getAbsolutePath());
  }

  @Override
  public String getCanonicalPath() throws IOException {
    return realFile.getCanonicalPath();
  }

  @Override
  public HSFile getCanonicalFile() throws IOException {
    return new HSFile(realFile.getCanonicalPath());
  }

  @Override
  public boolean setReadOnly() {
    return realFile.setReadOnly();
  }

  @Override
  public Path toPath() {
    return realFile.toPath();
  }

  @Override
  public HSFile getParentFile() {
    return new HSFile(getParent());
  }

  @Override
  public boolean renameTo(File file) {
    HSFile target = file instanceof HSFile ?
      (HSFile)file : new HSFile(file.getPath());
    return realFile.renameTo(target.realFile);
  }

  @Override
  public int compareTo(File file) {
    HSFile target = file instanceof HSFile ?
      (HSFile)file : new HSFile(file.getPath());
    return realFile.compareTo(target.realFile);
  }

  @Override
  public String[] list() {return  realFile.list();}

  @Override
  public HSFile[] listFiles() {
    File[] files = realFile.listFiles();
    if (files == null) return null;
    HSFile[] xFiles = new HSFile[files.length];
    int item;
    for (item = 0; item < files.length; item++)
      xFiles[item] = new HSFile(files[item].getPath());
    return xFiles;
  }

  @Override @Deprecated
  public HSFile[] listFiles(FilenameFilter filenameFilter) {
    // fill this in if you need it
    throw new UnsupportedOperationException("this operation is beyond the scope of this class");
  }

  @Override @Deprecated
  public String[] list(FilenameFilter filenameFilter) {
    // fill this in if you need it
    throw new UnsupportedOperationException("this operation is beyond the scope of this class");
  }

  @Override @Deprecated
  public HSFile[] listFiles(FileFilter fileFilter) {
    // fill this in if you need it
    throw new UnsupportedOperationException("this operation is beyond the scope of this class");
  }

}
import java.io.*;
导入java.net.URI;
导入java.nio.file.Path;
公共类HSFile扩展了java.io.File{
/*
为了使这个类按预期工作,我们需要在任何情况下进行干预
方法转换文件名,访问磁盘,
或者抛出异常。
*/
私有最终文件realFile;
私有最终字符串realDirectory;
公共静态字符串getCurrentDirectory(){
返回currentDirectory.getPath();
}
公共静态无效setCurrentDirectory(字符串currentDirectory)抛出
FileNotFoundException{
文件目标=新文件(currentDirectory);
如果(!target.exists())
抛出新的FileNotFoundException(“目标目录: