提问人:Stanisław 提问时间:7/17/2023 最后编辑:Stanisław 更新时间:7/18/2023 访问量:73
Java 程序在 .jar 可执行文件中使用时找不到路径
Java Program does not find paths when used in .jar executable
问:
当涉及到我的 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 上处理路径的方式不同。
答:
我在 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进行调试。
评论
到目前为止,我已经尝试使用我编写的 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.cmd
yt-dlp.sh
.cmd
.sh
至于您的方法,它似乎试图将单个二进制文件从 JAR 中复制到文件系统上,以便可以从那里执行。这可能行不通的原因有很多,其中包括:getFilePath()
yt-dlp
- 它首先依赖于被打包到你的 JAR 中。可以做出这样的安排,但我不希望默认情况下这样做。
yt-dlp
- 应用程序由多个文件和目录组成,但您只复制了一个文件和目录。
yt-dlp
- 将文件复制到磁盘不足以使其在 Mac 和 Linux 上可执行。
您有几个主要选项:
依赖于安装在系统的可执行搜索路径中,以便无需指定任何路径即可启动它。
yt-dlp
提供一种方法来配置应用程序的正确(完整)路径,并通过其完整路径执行它。
yt-dlp
为应用程序提供一种发现正确路径的方法。通常,这将依赖于 JAR 的位置和 的位置之间的已知关系。然后,您可以通过正确的路径启动它。
yt-dlp
其中一些选项更有可能基于与包装器应用程序的捆绑(但不是在 JAR 中)。其他人则更倾向于将您的应用程序与单独的 .yt-dlp
yt-dlp
评论
/
Project/src/