已解决 - 以编程方式执行新 jar 时使用 `new File(".")` 时出现问题

问题描述 投票:0回答:1

更新:

我的情况:

使用Java 17.0.8

我有一个应用程序 A.jar,它在启动时检查更新,下载更新,然后运行 B.jar 以用新下载的应用程序文件替换应用程序文件。

问题:

从A开始,当我运行B应用程序然后运行

exit(0)
时,A应用程序应该在JVM关闭后释放对A.jar文件的锁定,这样B应用程序就可以用新的更新版本替换这些文件。 相反,A.jar 文件保持锁定状态,B 应用程序无法使用更新覆盖 A 文件。

相反,如果 A 应用程序退出,然后我手动启动 B 应用程序,它就会按预期工作。 我还尝试运行 B 应用程序,使用

cmd /c
nohup 启动它,但它仍然没有释放 A 文件上的锁定...

调试:

创建一个新项目并编译此代码三次,一次用于 A.jar,一次用于 B.jar,最后一次用于 A2.jar,然后运行 A.jar,然后按预期成功更新到 A2.jar 版本.

public class Main implements Runnable {

    public static void main(String[] args) {

        SwingUtilities.invokeLater(new Main());
    }

    @Override
    public void run() {
        String x = "A"; //"A" for A.jar, "B" for B.jar and "A2" for A2.jar

        File dir = new File(".").getAbsoluteFile().getParentFile();
        File A = new File(dir.getAbsolutePath() + File.separator + "A.jar");
        File B = new File(dir.getAbsolutePath() + File.separator + "B.jar");
        File A2 = new File(dir.getAbsolutePath() + File.separator + "A2.jar");
        switch (x) {
            case "A" -> {
                JOptionPane.showMessageDialog(null, x + ": Lancio Aggiornamento!");
                try {
                    Runtime.getRuntime().exec("cmd /c java -jar \"" + B.getAbsolutePath() + "\"");
                    System.exit(0);
                } catch (IOException ex) {
                    JOptionPane.showMessageDialog(null, x + ": Aggiornamento Fallito!");
                }
            }
            case "B" -> {
                try {
                    JOptionPane.showMessageDialog(null, x + ": Sto Aggiornando!");
                    Files.copy(A2.toPath(), A.toPath(), StandardCopyOption.REPLACE_EXISTING);
                    A2.delete();
                    Runtime.getRuntime().exec("cmd /c java -jar \"" + A.getAbsolutePath() + "\"");
                    System.exit(0);
                } catch (IOException ex) {
                    JOptionPane.showMessageDialog(null, x + ": Aggiornamento Fallito!");
                }
            }
            case "A2" -> {
                B.delete();
                JOptionPane.showMessageDialog(null, x + ": Sono Aggiornamento!");
            }
            default -> { }
        }
    }

}

所以我想这是我的项目的问题。问题是有太多的代码和库来尝试找到罪魁祸首......

问题:

在我退出 JVM 并且它完全关闭,甚至从任务管理器中消失后,什么可能会导致主 .jar 文件保持锁定状态?难道它不应该释放 .jar 文件上的任何剩余锁定吗?

我知道如果我没有正确关闭文件流,那么它可能无法完全释放锁定,但我不会直接对 jar 文件本身执行任何操作...

java jar auto-update file-access
1个回答
0
投票

好吧,这很奇怪......

我克隆了应用程序项目,并开始删除一点,直到只剩下这个:

public class Main implements Runnable {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Main());
    }
    @Override
    public void run() {
        String dir = new File(".").getAbsoluteFile().getParentFile().getAbsolutePath() + File.separator;
        try {
            Runtime.getRuntime().exec("cmd /c java -jar \"" + dir + "Update" + File.separator + "Updater.jar\"");
        } catch (IOException ex) { }
        System.exit(0);
    }
}

在这一点上,毫无疑问,问题不是应用程序,而是更新程序本身......所以我也继续克隆该项目,并开始对其进行逆向工程,直到我终于知道问题出在哪里了

事情是这样的:

我的基本文件结构如下:

App Folder
├─ App.jar
├─ Update
│  ├─ Updater.jar
│  ├─ Data
│  │  ├─ NewApp.jar

App.jar
启动
Updater.jar
并退出。

Updater.jar
尝试找出它自己的位置路径,然后能够找到父
App Folder
的路径和子
Data
文件夹的路径。

要查找

.jar
当前目录,我可以通过执行
new File(".").getAbsoluteFile().getParentFile();
来获取它。这将生成一个“.”文件对象与正在运行的应用程序的
.jar
文件位于同一目录中。通过获取该对象的父对象,我基本上获得了当前应用程序的目录路径。 这就是打破!

如果我手动打开

Updater.jar
,路径是正确的,没有问题。

但是如果是

App.jar
打开了
Updater.jar
,那么出于某种原因,Updater应用调用的
new File(".")
将不再在
Updater.jar
目录中创建,而是在Updater所在的
App.jar
目录中创建被处决。

为了修复它,我暂时用

new File(context.getProtectionDomain().getCodeSource().getLocation().toURI())
替换了错误代码以获取当前的应用程序目录,它工作正常,但我必须找到一种“正确”的方法并真正更好地研究它,因为我开始也对这个解决方案产生怀疑!

老实说,这对我来说毫无意义,我觉得这更像是一个错误而不是一个功能......但尽管如此,我终于弄清楚了它的真相,现在一切都按预期工作了!

© www.soinside.com 2019 - 2024. All rights reserved.