如何在Java 8+;中正确实现更改目录支持;?
我正在编写一个脚本解释器/shell,我需要更改目录支持才能有效地完成这项工作 现在,我使用一个文件对象引用作为当前目录,并使用该文件对象解析所有相对路径。这是可行的,但问题是解释器使用的每个文件引用都有一个绝对路径。这在获取相对URI或发生错误时效果不佳,错误消息不会反映提供给脚本引擎的路径,这将使脚本调试非常“非直观”(正确的错误消息是关于错误输入的逐字逐句) 如果无法更改当前目录,Java的文件对象基本上已经过时。当然,如果java允许我在文件对象上指定我当前的目录,这不会是一个问题,但是我不知道有什么方法可以做到这一点,除了用这种特性支持扩展文件类 为了进一步加剧这种缺乏正确特性支持的逻辑谬误,我基本上面临着使用process builder运行流程的相同问题 我知道我已经“完成了”,但对我的项目来说,“正确完成”是非常重要的,这意味着透明 我已经看到了堆栈溢出的答案,上面说:修改系统属性:如何在Java 8+;中正确实现更改目录支持;?,java,Java,我正在编写一个脚本解释器/shell,我需要更改目录支持才能有效地完成这项工作 现在,我使用一个文件对象引用作为当前目录,并使用该文件对象解析所有相对路径。这是可行的,但问题是解释器使用的每个文件引用都有一个绝对路径。这在获取相对URI或发生错误时效果不佳,错误消息不会反映提供给脚本引擎的路径,这将使脚本调试非常“非直观”(正确的错误消息是关于错误输入的逐字逐句) 如果无法更改当前目录,Java的文件对象基本上已经过时。当然,如果java允许我在文件对象上指定我当前的目录,这不会是一个问题,但是
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(“目标目录: