You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

导出为可运行Jar后Java写入JSON文件失效问题求助

问题根源与解决方案

这个问题我太熟了——本质原因是Jar包是只读的压缩归档文件,你用getResource()获取的/character.json是Jar内部的资源条目,只能读取,根本没法直接修改写入。

在Eclipse里运行时,你的资源文件是存放在硬盘上的项目编译目录(比如target/classes)里,是真实的文件,所以读写都没问题;但打包成Jar后,这些资源就被压缩进Jar包了,相当于变成了压缩文件里的一个“文件”,你没法直接修改压缩包内部的内容。

解决思路

我们需要把JSON文件放到Jar包外部的可写位置,比如用户的个人文档目录、程序运行的当前目录,首次运行时如果外部没有这个文件,就从Jar里把默认的JSON复制过去,之后所有的读写操作都针对外部的这个文件。

修改后的代码示例

首先写一个方法来获取外部的JSON文件路径(这里用用户专属的应用文件夹,跨平台更友好):

private File getCharacterFile() {
    // 获取用户主目录,Windows是C:\Users\你的用户名,Linux/macOS是/home/你的用户名
    String userHome = System.getProperty("user.home");
    // 创建我们应用的专属文件夹,避免和其他文件混在一起
    File appDataDir = new File(userHome, ".my-survival-game");
    if (!appDataDir.exists()) {
        appDataDir.mkdirs(); // 如果文件夹不存在就创建
    }
    
    File characterFile = new File(appDataDir, "character.json");
    
    // 如果外部文件不存在,从Jar包中复制默认的character.json过去
    if (!characterFile.exists()) {
        try (InputStream defaultStream = getClass().getResourceAsStream("/character.json");
             OutputStream outStream = new FileOutputStream(characterFile)) {
            
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = defaultStream.read(buffer)) != -1) {
                outStream.write(buffer, 0, bytesRead);
            }
        } catch (IOException e) {
            e.printStackTrace(); // 实际项目里建议用日志框架代替printStackTrace
        }
    }
    
    return characterFile;
}

然后修改你的保存方法,直接操作外部文件:

public void saveCharacterInfo() {
    File charFile = getCharacterFile();
    // 读取外部的JSON文件,而不是Jar内部的
    JSONObject obj = JSONUtils.getJSONObjectFromFile(charFile.getAbsolutePath());
    
    // 你的属性赋值逻辑保持不变
    obj.put("day", c.getDay());
    obj.put("name", c.getCharName());
    obj.put("hp", c.getCharHp());
    obj.put("maxHp", c.getCharHpMax());
    obj.put("armor", c.getCharArmor());
    obj.put("speed", c.getCharSpeed());
    obj.put("strength", c.getCharStrength());
    obj.put("money", c.getCharMoney());
    obj.put("food", c.getCharFood());
    obj.put("maxFood", c.getCharMaxFood());
    obj.put("morale", c.getCharMorale());
    obj.put("bait", c.getCharBait());
    
    // 用try-with-resources自动关闭流,避免资源泄漏
    try (FileWriter writer = new FileWriter(charFile)) {
        writer.write(obj.toString());
        writer.flush();
    } catch (IOException e) {
        e.printStackTrace(); // 千万不要空catch!不然出问题你根本不知道哪里错了
    }
}

额外注意事项

  • 不要用空catch块:你原代码里catch (Exception e) {}会隐藏所有错误,调试时根本找不到问题,一定要至少打印异常信息。
  • 跨平台兼容性:用user.home比硬编码路径(比如C:\save\character.json)好太多,能适配Windows、Linux、macOS等系统。
  • 权限问题:用户主目录下的文件夹一般不会有权限问题,如果放在系统目录(比如C:\Program Files)可能会被系统阻止写入。

内容的提问来源于stack exchange,提问作者Thomas S.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:27:45