Java 程序在 .jar 可执行文件中使用时找不到路径

Java Program does not find paths when used in .jar executable

提问人:Stanisław 提问时间:7/17/2023 最后编辑:Stanisław 更新时间:7/18/2023 访问量:73

问:

当涉及到我的 Java 应用程序时,我遇到了一个问题。该应用程序使用 yt-dlp 从 Youtube 下载音乐,它基本上是 yt-dlp 的 GUI 版本。我遇到的问题仅存在于 MacOS 上,它在 Windows 上按预期工作。这是我下载方法代码的片段(这是特定于 MacOs 的方法,正如我之前提到的,我只在 MacOs 上遇到问题,而不是在 Windows 上遇到问题,因此我没有提供任何特定于 Windows 的代码):

下载方法:

private void download() {
Process process = null;
        try {
            ProcessBuilder processBuilder;
                String command =
                       "'Project/src/Zasoby/yt-dlp'" + " -f bestaudio " +
                        "-x --audio-format " + chosenFormat
                        + " --no-playlist --output '" + outputPath + "/%(title)s.%(ext)s ''"
                        + linkYT + "'";

            processBuilder = new ProcessBuilder("bash", "-c", command);

            processBuilder.inheritIO();
            process = processBuilder.start();
            process.waitFor();

            int exitCode = process.exitValue();

            System.out.println(exitCode + " EXIT CODE"); // a log for exit codes

            if (exitCode != 0) {
                InfoFrame ef = new InfoFrame(2);
                ef.setVisible(true);
           }
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
}

问题是,每当我不在我的IDE中尝试使用ProcessBuilder执行命令时(在我的IDE中它工作得很好 - 路径“Project/src/Zasoby/yt-dlp”被识别并且程序星标下载音乐),而是在通过.jar文件执行程序时,程序无法通过其提供的路径找到yt-dlp程序。

到目前为止,我已经尝试使用我编写的 getFilePath 方法提供路径,以确保我不需要指定“半完整”路径,这显然不适用于不同的 MacOs 计算机。

getFilePath 方法:

private Path getFilePath(String resourcePath) {
        try {
            InputStream inputStream = getResourceAsStream(resourcePath);
            Path tempFilePath = Files.createTempFile("temp", null);
            Files.copy(inputStream, tempFilePath, StandardCopyOption.REPLACE_EXISTING);
            return tempFilePath.toAbsolutePath();
        } catch (IOException e) {
            throw new RuntimeException("Failed to get resource file path: " + resourcePath, e);
        }
    }

下载方法中修改的命令 String:

Path ytDlpPathMac = getFilePath("Zasoby/yt-dlp");
String command =
             ytDlpPathMac.toString() + " -f bestaudio " +
             "-x --audio-format " + chosenFormat
             + " --no-playlist --output '" + outputPath + "/%(title)s.%(ext)s ''"
             + linkYT + "'";

此外,路径“Zasoby/yt-dlp”是“来自内容根目录的路径”,项目中的完整路径是“Project/src/Zasoby/yt-dlp” - 如果有帮助的话。我已经尝试了论坛上其他问题的其他解决方案,但是它们都没有解决问题。

我尝试在 MacOs 上使用 Xdebug 工具调试代码,我得到的输出是“..directory does not exist“ - 使用两种方法时,一种是具有”半完整“路径的方法,另一种是具有 getFilePath 方法的方法。正如我之前提到的,这只发生在 Mac 上,所以当涉及到 Java 本身时,也许在 MacOs 上处理路径的方式与在 Windows 上处理路径的方式不同。

Java Bash 文件 ytdl 下载-website-files

评论

2赞 Gordon Davisson 7/17/2023
任何不以此开头的路径都是相对路径,并且将从进程的当前工作目录开始解析...这几乎可以是任何东西(取决于启动您的程序的任何事情的心血来潮)。听起来您需要找到 .jar 文件的位置,并根据它所在的目录构建一个完整的路径。(不幸的是,我不知道如何在 java 中做到这一点。/
0赞 user207421 7/17/2023
路径不在 JAR 文件中,或者不应该在 JAR 文件中,但 JAR 文件不是文件系统,任意进程无法在其中找到文件。您可能需要单独分发有问题的文件。Project/src/

答:

-2赞 mgillett 7/17/2023 #1

我在 MacOS 上编程,每当我使用 Paths 时,我都会使用基本目录,即。

    private static final String BASEDIR = "/Users/<username>/devel/python_3/play/pandas/DNA/store_final";

否则,您的目录将相对于您的 Java 应用程序运行的位置(即其工作目录)。

我认为您可以使用以下打印语句来确定:

System.out.println("Working Directory = " + System.getProperty("user.dir"));

此外,我更喜欢直接从我的IDE进行调试。

评论

0赞 Gordon Davisson 7/18/2023
这是模棱两可和误导性的;“无论您的 Java 应用程序从哪里运行”将是其工作目录,不一定是文件所在的目录。
3赞 John Bollinger 7/17/2023 #2

到目前为止,我已经尝试使用我编写的 getFilePath 方法提供路径 为了确保我不需要指定“半完整”路径 这显然无法在不同的 MacOs 计算机上运行。

我不知道你所说的“半完整路径”是什么意思,但如果你想运行一个外部程序,那么该程序必须是

  • 在系统的可执行文件搜索路径中,或
  • 通过它的绝对路径指定,或者
  • 通过相对于主机程序的当前工作目录的路径指定。

问题是,每当我尝试使用 ProcessBuilder 不在我的 IDE 中(在我的 IDE 中它工作得很好 - 路径“Project/src/Zasoby/yt-dlp”被识别,程序已加星 下载音乐),而不是在通过 .jar 执行程序时 文件,程序无法通过其提供的 yt-dlp 程序找到 路径。

Project/src/Zasoby/yt-dlp是相对路径。它是否适用于启动程序取决于启动 Java 程序的工作目录(不一定是包含 JAR 文件或任何类文件的文件夹),该相对路径将针对该工作目录进行解析。这并不特定于使用 JAR 文件或任何操作系统;只是对于从 IDE 启动时使用的工作目录来说,这恰好是正确的。Project/src/Zasoby/yt-dlp

此外,看起来 yt-dlp 提供了 Windows 和 Unix 包装脚本,分别命名为 和 。您可以在 Windows 上忽略该扩展,但不能在 MacOS 或 Linux 上忽略该扩展。yt-dlp.cmdyt-dlp.sh.cmd.sh

至于您的方法,它似乎试图将单个二进制文件从 JAR 中复制到文件系统上,以便可以从那里执行。这可能行不通的原因有很多,其中包括:getFilePath()yt-dlp

  • 它首先依赖于被打包到你的 JAR 中。可以做出这样的安排,但我不希望默认情况下这样做。yt-dlp
  • 应用程序由多个文件和目录组成,但您只复制了一个文件和目录。yt-dlp
  • 将文件复制到磁盘不足以使其在 Mac 和 Linux 上可执行。

您有几个主要选项:

  1. 依赖于安装在系统的可执行搜索路径中,以便无需指定任何路径即可启动它。yt-dlp

  2. 提供一种方法来配置应用程序的正确(完整)路径,并通过其完整路径执行它。yt-dlp

  3. 为应用程序提供一种发现正确路径的方法。通常,这将依赖于 JAR 的位置和 的位置之间的已知关系。然后,您可以通过正确的路径启动它。yt-dlp

其中一些选项更有可能基于与包装器应用程序的捆绑(但不是在 JAR 中)。其他人则更倾向于将您的应用程序与单独的 .yt-dlpyt-dlp

评论

0赞 Hovercraft Full Of Eels 7/17/2023
最后,一个体面的答案。谢谢