【问题标题】:File path of current execution replacing space and other characters [duplicate]当前执行替换空格和其他字符的文件路径[重复]
【发布时间】:2020-09-24 02:11:13
【问题描述】:

在我的程序中我做了

File jarFile = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().getPath());
execPath = String.valueOf(jarFile.getParentFile());

将 execPath = 获取到当前执行的路径(最终的 .exe 程序所在的位置)。 Wich 是我的主类的一个属性,我用它来进行一些文件操作和读取。

但是,

在某些带有空格或重音符号的文件夹中运行程序时,execPath 的值将替换为 %number,如下所示

C:\Users\Hugo\OneDrive%20-%20Funda%c3%a7%c3%a3o%20para%20Inova%c3%a7%c3%b5es%20Tecnol%c3%b3gicas%20-%20FITec\Redes\自动通信路由器\

在哪里

OneDrive%20-%20Funda%c3%a7%c3%a3o%20para%20Inova%c3%a7%c3%b5es%20Tecnol%c3%b3gicas%20-%20FITec

应该是

OneDrive - Fundação para Inovações Tecnológicas - FITec

我想知道是否有可能摆脱我的 execPath 属性的这种烦人的替换。

【问题讨论】:

标签: java


【解决方案1】:

不要调用 URL.getPath() 方法。如您现在所见,它返回有效的文件名。它只返回 URL 的路径部分(方案和主机之后的部分),所有百分比转义都完好无损。

将 URL 转换为文件的正确方法是 converting it to a URI,然后是 constructing a File from that URI

所以,正确的代码应该是这样的:

CodeSource source = Main.class.getProtectionDomain().getCodeSource();
if (source != null) {
    try {
        File jarFile = new File(source.getLocation().toURI());
        execPath = String.valueOf(jarFile.getParentFile());
    } catch (URISyntaxException e) {
        throw new RuntimeException(e);
    }
}

注意检查是否为空。 The code source can be null,取决于 ClassLoader 愿意并且能够将多少信息传递给它创建的 ProtectionDomain。这意味着尝试在运行时查找 .jar 文件的位置是不可靠的。

如果您想将本机可执行文件与 .jar 文件捆绑在一起,这里有一些更可靠的选项:

  • 在您的 .jar 文件中包含一个脚本(Windows 的批处理文件,其他系统的 shell 脚本),该文件将系统属性传递给程序,其中包含可执行文件的位置。
  • 将可执行文件捆绑在 .jar 文件中,并在运行时将它们复制到临时文件并使其可执行。

第一种方法将使用系统来确定目录,因为 是可靠的,并将其传递给程序。例如,在 Windows 中:

set execdir=%~dp0..\..
javaw.exe "-Dexecutable.dir=%here%" -jar MyApplication.jar

在 Linux 中:

execdir=`dirname $0`/..
java "-Dexecutable.dir=$execdir" -jar MyApplication.jar

第二种方法需要创建包含可执行文件的 .jar 文件,然后在要运行它们时将它们复制到 .jar 之外:

Path execDir = Files.createTempDirectory(null);
execPath = execDir.toString();

String[] executables;
String os = System.getProperty("os.name");
if (os.contains("Windows")) {
    executables = new String[] {
        "windows/foo.exe", "windows/bar.exe", "windows/baz.exe"
    };
} else if (os.contains("Mac")) {
    executables = new String[] {
        "mac/foo", "mac/bar", "mac/baz"
    };
} else {
    executables = new String[] {
        "linux/foo", "linux/bar", "linux/baz"
    };
}

for (String executable : executables) {
    String baseName = executable.substring(executable.lastIndexOf('/') + 1);
    Path newFile = execDir.resolve(baseName);

    try (InputStream executable =
        Main.class.getResourceAsStream(executable)) {

        Files.copy(executable, newFile);
    }
    if (Files.getFileStore(newFile).supportsFileAttributeView(
        PosixFileAttributeView.class)) {

        Set<PosixFilePermission> perms =
            Files.getPosixFilePermissions(newFile);
        perms.add(PosixFilePermission.OWNER_EXECUTE);
        Files.setPosixFilePermissions(newFile, perms);
    }
}

【讨论】:

  • 感谢您的回答,但我想您的解决方案比我的问题更复杂,或者我真的是菜鸟,正如我在 cmets 中提到的,解码 URL 对我来说效果很好。
猜你喜欢
  • 2018-10-04
  • 2013-07-10
  • 2010-11-14
  • 1970-01-01
  • 2012-09-29
  • 2019-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多