jar文件没有更新文件中的值

时间:2016-12-31 18:57:40

标签: debugging javafx jar executable-jar

我有一个javafx项目,我正准备分发。该项目完全可以从NetBeans中的调试器中完成。我在Linux上工作。

但是当我从jar文件运行项目时,所有其他功能中都有一个功能不起作用。该函数应该在单击按钮时打开设置文件,并将某些值从true更改为false。

我更改了设置文件的位置并尝试了谷歌,但都无济于事。

我仍然是java,fx,netbeans和java(不是那么多编程)的新手,并且是我第一次体验。

知道为什么会这样吗?

@FXML
private void openSettingsFile(ActionEvent event) throws IOException {

    // this test works ....
    ProcessBuilder processBuilder = new ProcessBuilder("terminal");
    processBuilder.start();

    // this part only replaces the values when I use the debugger ..
    Path path = Paths.get("src/desktop_launcher/Settings.java");
    Charset charset = StandardCharsets.UTF_8;
    String content = new String(Files.readAllBytes(path));
    content = content.replaceAll(" \"true\"" , " \"false\"");
    Files.write(path, content.getBytes(charset));

1 个答案:

答案 0 :(得分:1)

您的方法(据我所知,尝试以编程方式更改生成属性文件的源文件)在部署时将无法正常工作,原因有很多。

首先,源文件通常在运行时不可用:您的jar文件包含运行应用程序所需的类文件和其他资源,但通常不包含源代码(并且它不适合包含它在应用程序中,一般而言)。

其次,您尝试从传递给Paths.get(..)的相对路径中找到此文件。这将解析相对于工作目录,这基本上是任意的(基本上是#34;应用程序从"运行)。因此,即使源代码在运行时可用,这也不是找到它的可靠方法。 (我的猜测是你的调试器运行时工作目录偶然设置为src的父目录,但是当你运行jar文件时,工作目录最可能的位置是jar文件所在的目录但这只是猜测:它实际上取决于IDE,调试器等的配置。)

第三,也许最重要的是,即使代码确实找到了源文件并重写它,它就会做到。下次从jar文件中执行应用程序时,它不会神奇地知道有一个新版本的源代码必须编译,然后生成的类文件合并到jar文件中。所以你还必须包含代码来编译源代码的新版本(你将在哪里获得编译器?AFAIK并非所有Java运行时都包含编译器)然后以编程方式将新类文件插入到jar文件中(你怎么知道jar文件的位置:这当然是非平凡的,我不认为它可以以可靠的方式完成)。如果当前用户没有权限写入包含jar的目录(这是一种非常常见的场景......),该怎么办?

加载和保存启动配置值的常用方法是使用java.util.Properties API。您需要一个外部位置来存储属性文件,您可以确定该文件存在于用户的计算机上:一种方便的方法是在用户的主目录中创建特定于应用程序的目录。可以通过System.getProperty("user.home");访问用户的主目录(系统属性user.homeguaranteed to exist之一。)。

我建议使用单独的类来管理配置属性。例如:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.Properties;

public class PropertiesAccessor {

    private static final Path USER_HOME = Paths.get(System.getProperty("user.home"));

    private Properties props ;
    private Path path ;

    public PropertiesAccessor(String relativePath) {
        path = USER_HOME.resolve(relativePath);

        props = new Properties();

        if (Files.exists(path)) {
            try {
                props.load(Files.newBufferedReader(path));
            } catch (IOException exc) {
                System.err.println("Warning: could not load properties file. Using defaults.");
                exc.printStackTrace(System.err);
                loadDefaults();
            }
        } else {
            loadDefaults();
        }

    }

    public Boolean getBooleanValue(String key) {
        String value = props.getProperty(key);
        return value == null ? null : Boolean.valueOf(value) ;
    }

    public void updateBooleanValue(String key, boolean value) {
        props.setProperty(key, Boolean.toString(value));
    }

    public void writeProperties() throws IOException {
        if (! Files.exists(path)) {
            Files.createDirectories(path.getParent());
            Files.createFile(path);
        }
        props.store(Files.newBufferedWriter(path), "Properties updated "+LocalDateTime.now());
    }

    private final void loadDefaults() {
        // in real life, you might keep a default properties file bundled with
        // the application and read that here, e.g. 
        // props.load(getClass().getResourceAsStream("/default-startup.properties"));

        props.setProperty("config.value1", "true");
        props.setProperty("config.value2", "false");
    }
}

现在您可以在您的应用程序中使用它。只需在init()方法中加载属性,然后将其保存回stop()方法。 请注意,执行此操作会在您的主目录中创建一个名为.myApp的目录,并在其中创建一个名为startup.properties的文件。

import java.io.IOException;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class StartupPropertiesExample extends Application {

    private PropertiesAccessor config ;

    private CheckBox value1 ;
    private CheckBox value2 ;

    @Override
    public void init() {
        config = new PropertiesAccessor(".myApp/startup.properties");
    }

    @Override
    public void start(Stage primaryStage) {
        value1 = new CheckBox("Value 1");
        value2 = new CheckBox("Value 2");
        value1.setSelected(config.getBooleanValue("config.value1"));
        value2.setSelected(config.getBooleanValue("config.value2"));

        Button exit = new Button("Exit");
        exit.setOnAction(e -> Platform.exit());

        VBox root = new VBox(10, value1, value2, exit);
        root.setPadding(new Insets(10));

        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    @Override
    public void stop() {
        config.updateBooleanValue("config.value1", value1.isSelected());
        config.updateBooleanValue("config.value2", value2.isSelected());
        try {
            config.writeProperties();
        } catch (IOException exc) {
            System.err.println("Warning: could not save properties");
            exc.printStackTrace(System.err);
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}
相关问题