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

如何在Jar文件内或其旁执行脚本并处理相关文件?

问题解决思路与方案

核心问题说明

打包成Jar后,/src/main/resources/这类路径完全失效——Jar是压缩文件,内部资源无法直接作为文件系统路径被ProcessBuilder调用,而且Jar内的文件只读,根本无法在Jar内部创建或修改令牌、文本、JSON这类文件。

最佳方案:分离可执行脚本与可修改文件到外部目录

结合你的服务器目录结构(/Deployments/Data),把所有需要执行、修改的文件都放到Data目录下,具体步骤:


1. 提取Jar内的脚本到外部Data目录

启动程序时,先把Jar中打包的hello.bat脚本复制到/Deployments/Data目录(确保该目录有读写权限),再执行这个外部的脚本文件:

// 定义外部Data目录路径,建议通过系统参数或配置文件传入,避免硬编码
private final String EXTERNAL_DATA_DIR = "/Deployments/Data/";
private final String SCRIPT_NAME = "hello.bat";

public void runScript4() {
    // 先将Jar内的脚本提取到外部目录
    extractResourceToExternalDir(SCRIPT_NAME, EXTERNAL_DATA_DIR);
    
    String scriptPath = EXTERNAL_DATA_DIR + SCRIPT_NAME;
    try {
        Process process = new ProcessBuilder(scriptPath).start();
        process.waitFor();
        System.out.println("Script executing...");
        
        BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
        String inputLine;
        StringBuilder result = new StringBuilder(); // 用StringBuilder替代String拼接,提升效率
        while ((inputLine = in.readLine()) != null) {
            System.out.println(inputLine);
            result.append(inputLine);
        }
        in.close();
    } catch (IOException | InterruptedException e) {
        e.printStackTrace();
    }
}

// 提取Jar内资源到外部目录的工具方法
private void extractResourceToExternalDir(String resourceName, String targetDir) {
    File targetFile = new File(targetDir + resourceName);
    // 若文件已存在,跳过提取(避免每次启动重复覆盖)
    if (targetFile.exists()) {
        return;
    }
    
    // 创建目标目录(如果不存在)
    new File(targetDir).mkdirs();
    
    // 从Jar读取资源并写入外部文件
    try (InputStream resourceStream = getClass().getResourceAsStream("/" + resourceName);
         FileOutputStream outputStream = new FileOutputStream(targetFile)) {
        if (resourceStream == null) {
            throw new IOException("Resource " + resourceName + " not found in Jar");
        }
        byte[] buffer = new byte[1024];
        int bytesRead;
        while ((bytesRead = resourceStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, bytesRead);
        }
        // 若为Linux系统,需给脚本添加可执行权限
        targetFile.setExecutable(true);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

2. 所有可修改文件(令牌、txt、JSON)都放在Data目录

  • 本地开发时,可在项目根目录创建Data文件夹,将txt/JSON文件放入其中,再配置IDE把Data设为资源目录,让本地运行时直接读取该目录,和线上环境保持一致。
  • 线上部署时,将初始的txt/JSON文件放到/Deployments/Data目录,程序直接读写该目录下的文件,示例代码:
// 读取Data目录下的文本文件
public String readTxtFile() throws IOException {
    File txtFile = new File(EXTERNAL_DATA_DIR + "data.txt");
    return Files.readString(txtFile.toPath());
}

// 修改Data目录下的JSON文件
public void updateJsonFile(String newContent) throws IOException {
    File jsonFile = new File(EXTERNAL_DATA_DIR + "config.json");
    Files.writeString(jsonFile.toPath(), newContent);
}

3. 避免硬编码路径的小技巧

不要直接写死/Deployments/Data,可通过JVM启动参数传入,比如:

java -jar project.jar -Ddata.dir=/Deployments/Data

然后在代码中读取:

private final String EXTERNAL_DATA_DIR = System.getProperty("data.dir", "./Data/");

这样本地和线上的路径可灵活配置,无需修改代码。


关于Jar内修改文件的疑问

绝对不建议尝试在Jar内创建或修改文件:

  1. Jar运行时会被JVM加载,多数情况下文件处于锁定状态,无法修改。
  2. 即使成功修改,下次重新部署Jar时,所有修改内容会被覆盖。
  3. 若Jar带有数字签名,修改后签名会失效,导致Jar无法被JVM加载。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 14:35:19