我有一个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));
答案 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.home
是guaranteed 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);
}
}