Search code examples
javafilejavafxappdata

Not able to write to AppData


I'm making a small game in JavaFX and I want a Highscore-system. Because I'm not that good with databases, I wrote the data to a textfile. But that easy editable, so I would want to write it to a textfile in AppData. So I tried with this line:

File file = new File(System.getenv("AppData") + "\\" + [Namefoler\\NameFile]);

But it keeps saying that I do not have acces to that folder. Writing to and off a file is no problem so my system works fine if I just write it to a textfile in the same directory as my jar. But it keeps throwing these errors.

Does someone know how I can prevent this, or a better solution for my problem?

Thanks in advance


Solution

  • This answer is not to do with AppData, but you did ask about other solutions, so this is one based upon the Preferences API. The sample is for a preferences based API storage for a high-score system. The sample does not encrypt data.

    You mention in your question that you are worried about the user modifying the preferences to fudge high scores. Encrypting or hiding data for a client application such that a user is not able to modify the data is a tricky proposition, so I won't go into how to do that here. If that is a requirement for you, then you can research other info on the internet for methods to accomplish that.

    score system

    ScoreStorage.java

    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    
    import java.util.prefs.BackingStoreException;
    import java.util.prefs.Preferences;
    
    public class ScoreStorage {
        private static final int MAX_NUM_SCORES = 3;
    
        private static final String SCORE_PREFERENCE_KEY_PREFIX = "score-";
    
        private ObservableList<Integer> scores = FXCollections.observableArrayList();
        private Preferences scorePreferences = Preferences.userNodeForPackage(
            ScoreStorage.class
        );
    
        public ScoreStorage() throws BackingStoreException {
            for (String key: scorePreferences.keys()) {
                scores.add(scorePreferences.getInt(key, 0));
            }
        }
    
        public ObservableList<Integer> getUnmodifiableScores() {
            return FXCollections.unmodifiableObservableList(scores);
        }
    
        public void clearScores() {
            scores.clear();
            storeScores();
        }
    
        public void recordScore(int score) {
            int i = 0;
            while (i < MAX_NUM_SCORES && i < scores.size() && scores.get(i) >= score) {
                i++;
            }
    
            if (i < MAX_NUM_SCORES) {
                if (scores.size() == MAX_NUM_SCORES) {
                    scores.remove(scores.size() - 1);
                }
                scores.add(i, score);
                storeScores();
            }
        }
    
        private void storeScores() {
            int i = 0;
            for (int score: scores) {
                scorePreferences.putInt(SCORE_PREFERENCE_KEY_PREFIX + i, score);
                i++;
            }
            while (i < MAX_NUM_SCORES) {
                scorePreferences.remove(SCORE_PREFERENCE_KEY_PREFIX + i);
                i++;
            }
        }
    }
    

    HighScoreApp.java

    Test harness:

    import javafx.application.Application;
    import javafx.geometry.*;
    import javafx.scene.Scene;
    import javafx.scene.control.*;
    import javafx.scene.layout.*;
    import javafx.stage.Stage;
    
    import java.util.Random;
    import java.util.prefs.BackingStoreException;
    
    public class HighScoreApp extends Application {
    
        private static ScoreStorage scoreStorage;
    
        private Random random = new Random(42);
    
        @Override
        public void start(Stage stage) throws Exception {
            ListView<Integer> scoreList = new ListView<>(scoreStorage.getUnmodifiableScores());
            scoreList.setPrefHeight(150);
    
            Label lastScoreLabel = new Label();
    
            Button generateScore = new Button("Generate new score");
            generateScore.setOnAction(event -> {
                int lastScore = random.nextInt(11_000);
                lastScoreLabel.setText("" + lastScore);
                scoreStorage.recordScore(lastScore);
            });
    
            Button clearScores = new Button("Clear scores");
            clearScores.setOnAction(event -> scoreStorage.clearScores());
    
            HBox scoreGenerator = new HBox(10, generateScore, lastScoreLabel);
            scoreGenerator.setAlignment(Pos.BASELINE_LEFT);
    
            VBox layout = new VBox(10, scoreGenerator, scoreList, clearScores);
            layout.setPadding(new Insets(10));
    
            stage.setScene(new Scene(layout));
            stage.show();
        }
    
        public static void main(String[] args) throws BackingStoreException {
            scoreStorage = new ScoreStorage();
            launch(args);
        }
    }