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

Maven项目打包成JAR后无法写入文件,如何解决?

解决JAR包内文件无法写入的问题

核心原因

JAR本质是ZIP压缩包,程序运行时JAR会被JVM加载,无法直接对JAR内部的文件进行写入操作。IDE中运行时,test.txt是磁盘上的独立文件,所以能正常写入;打包成JAR后,文件变成了JAR包内的压缩条目,自然写不进去。


方案1:将文件移到JAR外部存储(推荐)

这是最实用的解决方案,把需要修改的文件放到JAR外面的磁盘路径,读写都针对外部文件。如果需要初始内容,启动时从JAR里把初始文件复制到外部即可。

修改后的完整代码:

import java.io.*;
import java.nio.file.Files;
import java.util.Scanner;

public class Main {
    // 外部文件路径,比如程序运行目录下的data/test.txt
    private static final String EXTERNAL_FILE_PATH = "data/test.txt";

    public static void main(String[] args) {
        Main mainTest = new Main();
        // 确保外部文件存在,不存在就从JAR复制初始文件
        mainTest.ensureExternalFileExists();
        mainTest.test("hello world");
        System.out.println(mainTest.test2());
    }

    private void ensureExternalFileExists() {
        File externalFile = new File(EXTERNAL_FILE_PATH);
        if (!externalFile.exists()) {
            // 创建父目录
            externalFile.getParentFile().mkdirs();
            // 从JAR里复制初始test.txt到外部
            try (InputStream jarInputStream = getClass().getClassLoader().getResourceAsStream("test.txt");
                 OutputStream fileOutputStream = new FileOutputStream(externalFile)) {
                if (jarInputStream != null) {
                    Files.copy(jarInputStream, externalFile.toPath());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void test(String text) {
        try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(EXTERNAL_FILE_PATH))) {
            bufferedWriter.write(text);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private String test2() {
        try (Scanner scanner = new Scanner(new File(EXTERNAL_FILE_PATH))) {
            String line = "";
            while (scanner.hasNextLine()) {
                line = scanner.nextLine();
            }
            return line;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}

方案2:动态修改JAR文件(不推荐)

如果非要修改JAR内部文件,得注意:运行中的JAR被JVM锁定,无法直接修改,只能在程序退出后,或者用单独进程来操作。可以用Java的ZIP API重新生成JAR,替换目标文件。

演示代码(谨慎使用):

import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class JarModifier {
    public static void updateFileInJar(String jarPath, String entryName, String newContent) throws IOException {
        // 创建临时文件存修改后的JAR
        File tempJar = File.createTempFile("temp", ".jar");
        try (FileInputStream fis = new FileInputStream(jarPath);
             FileOutputStream fos = new FileOutputStream(tempJar);
             ZipOutputStream zos = new ZipOutputStream(fos)) {

            java.util.zip.ZipInputStream zis = new java.util.zip.ZipInputStream(fis);
            ZipEntry entry;
            // 遍历原JAR所有条目
            while ((entry = zis.getNextEntry()) != null) {
                if (!entry.getName().equals(entryName)) {
                    // 复制非目标条目到临时JAR
                    zos.putNextEntry(new ZipEntry(entry.getName()));
                    byte[] buffer = new byte[1024];
                    int len;
                    while ((len = zis.read(buffer)) > 0) {
                        zos.write(buffer, 0, len);
                    }
                    zos.closeEntry();
                } else {
                    // 写入新内容到目标条目
                    zos.putNextEntry(new ZipEntry(entryName));
                    zos.write(newContent.getBytes());
                    zos.closeEntry();
                }
                zis.closeEntry();
            }
            zis.close();
        }

        // 替换原JAR文件
        File originalJar = new File(jarPath);
        if (originalJar.delete() && tempJar.renameTo(originalJar)) {
            System.out.println("JAR文件已更新");
        } else {
            tempJar.delete();
            throw new IOException("替换原JAR失败");
        }
    }

    // 使用示例:单独执行该类,或者程序退出后调用
    public static void main(String[] args) {
        try {
            updateFileInJar("your-app.jar", "test.txt", "hello world");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

总结

优先用方案1,简单稳定,符合Java程序的常规使用逻辑;方案2仅适用于特殊场景,存在文件锁定、JAR损坏的风险,一般不建议用。

内容的提问来源于stack exchange,提问作者Valloyd

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 22:48:20