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

如何在.jar文件内部运行已编译的C程序

操作系统无法直接加载运行.jar压缩包内部的可执行文件,所有可行方案的核心逻辑都是运行前将jar内的C程序二进制资源释放到本地文件系统的可访问路径,调用完成后自动清理,不存在不落地文件直接运行jar内C程序的实现方式,不用在这类思路上浪费时间。

具体实现步骤

1. 提前做好多环境适配准备

  • 针对你要支持的操作系统、CPU架构,提前编译好对应版本的C程序,全部作为资源文件打包进jar,建议按/native/${操作系统}/${CPU架构}/程序名的目录结构存放,比如/native/linux/amd64/mytool、/native/win/amd64/mytool.exe,避免跨架构运行失败。
  • 如果你用Maven/Gradle打包,记得关闭二进制资源的文本过滤规则,防止编译好的C程序被打包插件破坏。

2. 运行时匹配对应资源并释放到临时目录

这一步要避开几个常见坑:Windows下临时文件必须带.exe后缀才能正常运行;类Unix系统下必须给释放的文件加可执行权限;要注册退出钩子自动清理临时文件,避免垃圾残留。
参考实现代码:

import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.Set;

public class NativeExecLoader {
    public static void main(String[] args) throws IOException {
        // 识别当前运行环境
        String os = System.getProperty("os.name").toLowerCase();
        String arch = System.getProperty("os.arch").toLowerCase();
        String resourcePath;
        String execSuffix = "";

        if (os.contains("win")) {
            execSuffix = ".exe";
            resourcePath = String.format("/native/win/%s/mytool%s", arch, execSuffix);
        } else if (os.contains("nix") || os.contains("nux")) {
            resourcePath = String.format("/native/linux/%s/mytool", arch);
        } else if (os.contains("mac")) {
            resourcePath = String.format("/native/mac/%s/mytool", arch);
        } else {
            throw new UnsupportedOperationException("不支持当前运行环境: " + os);
        }

        // 读取jar内的二进制资源
        try (InputStream resourceStream = NativeExecLoader.class.getResourceAsStream(resourcePath)) {
            if (resourceStream == null) {
                throw new FileNotFoundException("未找到对应环境的原生程序: " + resourcePath);
            }
            // 创建系统临时目录下的临时文件
            Path tempExec = Files.createTempFile("native_c_", execSuffix);
            // 注册JVM退出时自动删除临时文件
            tempExec.toFile().deleteOnExit();
            // 拷贝二进制内容到临时文件
            Files.copy(resourceStream, tempExec, StandardCopyOption.REPLACE_EXISTING);
            // 非Windows系统需要给文件加可执行权限
            if (!os.contains("win")) {
                Set<PosixFilePermission> permissions = PosixFilePermissions.fromString("rwx------");
                Files.setPosixFilePermissions(tempExec, permissions);
            }
            // 拿到本地可执行文件的绝对路径,供后续调用
            String execAbsolutePath = tempExec.toAbsolutePath().toString();

            // 后续调用逻辑和你之前调用外部C程序的逻辑完全一致
            ProcessBuilder pb = new ProcessBuilder(execAbsolutePath, "参数1", "参数2");
            pb.redirectErrorStream(true);
            Process proc = pb.start();
            // 读取输出、等待进程退出的逻辑保持原有写法即可
        }
    }
}
常见问题处理
  • 如果你的C程序依赖额外的动态链接库(.so/.dll/.dylib),需要把这些依赖库按同样逻辑释放到同一个临时目录,启动进程前把临时目录加到对应系统的库搜索路径环境变量:Windows追加到PATH、Linux追加到LD_LIBRARY_PATH、macOS追加到DYLD_LIBRARY_PATH。
  • 不要尝试通过管道、特殊文件系统路径直接读取jar内的二进制流作为可执行文件运行,绝大多数操作系统的程序加载器不支持从非实体文件加载可执行段,这类方案都跑不通。
  • 如果遇到权限拒绝、文件无法运行的问题,优先检查临时文件权限、杀毒软件拦截规则,部分企业杀毒软件会禁止程序从临时目录启动可执行文件,这种场景可以把临时文件创建到用户目录下的专属缓存路径。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 12:18:24