Jar包中FileOutputStream无法找到txt文件,求技术解决方案
问题分析与解决方案
这个问题其实挺常见的——IDE里跑着一切正常,打包成Jar就找不到文件,核心原因主要有两个:
1. 路径逻辑完全错配
你用的"src/resources/highscore.txt"是IDE项目结构里的相对路径,但打包成Jar后,这个路径根本不存在:Jar文件不会保留src目录,你的资源文件会被放到Jar的根目录(类路径根路径)。更关键的是,Jar是压缩文件,你没法用FileOutputStream直接写入Jar内部的文件,哪怕路径写对了也不行,因为Jar内的资源是只读的。
2. getResource()的用法误区
this.getClass().getResources(path)是用来读取类路径下的只读资源的(比如配置文件、静态图片),但它不能用来定位可写入的文件——因为写入需要一个在文件系统中真实存在、且有写入权限的路径,而不是Jar包内部的资源路径。
正确解决方案:把数据文件放到外部可写目录
最佳实践是把用户数据(比如高分榜)存到操作系统的用户专属可写目录里,比如Windows的C:\Users\[你的用户名]\AppData\Roaming,或者Linux/macOS的~/.your-app-name。不管是IDE运行还是Jar运行,都能找到稳定的可写入位置。
改造后的代码示例
public void setPlayer() { ArrayList<Player> playerArrayList = getPlayers(); Player player = new Player(); player.name = ViewManager.name; player.score = Collision.points; playerArrayList.add(player); // 步骤1:获取外部可写目录(这里用用户home目录下的专属文件夹) File appDataDir = new File(System.getProperty("user.home"), ".my-game-highscores"); if (!appDataDir.exists()) { appDataDir.mkdirs(); // 目录不存在就创建 } File highScoreFile = new File(appDataDir, "highscore.txt"); // 步骤2:写入数据到外部文件(用try-with-resources自动关流) try (FileOutputStream fileOut = new FileOutputStream(highScoreFile); ObjectOutputStream out = new ObjectOutputStream(fileOut)) { for(Player player1 : playerArrayList){ out.writeObject(player1); } } catch (IOException e) { e.printStackTrace(); } } // 对应的读取方法也要同步改造 public ArrayList<Player> getPlayers() { ArrayList<Player> playerArrayList = new ArrayList<>(); File appDataDir = new File(System.getProperty("user.home"), ".my-game-highscores"); File highScoreFile = new File(appDataDir, "highscore.txt"); if (!highScoreFile.exists()) { return playerArrayList; // 文件不存在时返回空列表 } try (FileInputStream fileIn = new FileInputStream(highScoreFile); ObjectInputStream in = new ObjectInputStream(fileIn)) { while (true) { try { Player p = (Player) in.readObject(); playerArrayList.add(p); } catch (EOFException e) { break; // 读到文件末尾就退出循环 } } } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } return playerArrayList; }
额外提醒
- 确保
Player类已经实现了Serializable接口,否则序列化会失败(你IDE里能运行,应该已经实现了,但还是提一句)。 - 用
try-with-resources语法自动关闭流,比手动调用close()更安全,能避免资源泄漏。 - 给你的应用专属目录起个辨识度高的名字,比如
".space-war-highscores",避免和其他应用的文件冲突。
内容的提问来源于stack exchange,提问作者user10751443
相关产品推荐
相关产品推荐

