导出为可运行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.
相关产品推荐
相关产品推荐

