如何在 C 语言中正确读取 Java 的 .jmod 文件

轻瑶大大_9371

轻瑶大大_9371

2026-10-31

734人浏览

原创

如何在 C 语言中正确读取 Java 的 .jmod 文件

.jmod 文件虽底层基于 ZIP 格式,但并非标准 ZIP(不以 PK 开头),而是以 JM\x01\x00 自定义头起始;直接用 libzip 等标准 ZIP 库会失败,需跳过头部或改用 jmod 工具调用。

`.jmod` 文件虽底层基于 zip 格式,但并非标准 zip(不以 `pk` 开头),而是以 `jm\x01\x00` 自定义头起始;直接用 `libzip` 等标准 zip 库会失败,需跳过头部或改用 `jmod` 工具调用。

Java 9 引入的 .jmod 文件是 OpenJDK 官方定义的模块封装格式,用于 JDK 内部构建与链接(如 jlink),并非面向用户或第三方工具设计的通用归档格式。其核心特性在于:它是一个“带前缀的 ZIP”——前 4 字节为自定义魔数 JM\x01\x00(ASCII 0x4A 0x4D + 版本号),之后才是标准 ZIP 数据流。

正因为如此,系统命令 unzip 能成功解压 .jmod 文件——它遵循 ZIP 规范的原始语义:从文件末尾反向查找中央目录结构(Central Directory),完全忽略开头任意字节(包括 JM 头)。而大多数 ZIP 库(如 libzip、minizip、zlib 的高层封装)默认依赖文件开头的 PK\x03\x04 或 PK\x05\x06 签名进行快速识别和校验,一旦未匹配即报错 "Not a zip archive"。

✅ 正确处理方案(按推荐优先级排序)

1. 首选:调用 jmod 命令行工具(最可靠、符合设计意图)

OpenJDK 提供的 jmod 工具专为解析和操作 .jmod 文件而生,支持列出内容、提取类、验证结构等。在 C 程序中可通过 popen() 安全调用:

#include <stdio.h>
#include <stdlib.h>

int list_jmod_contents(const char* jmod_path) {
    char cmd[1024];
    snprintf(cmd, sizeof(cmd), "jmod list \"%s\" 2>/dev/null", jmod_path);
    FILE* fp = popen(cmd, "r");
    if (!fp) return -1;

    char line[512];
    while (fgets(line, sizeof(line), fp)) {
        printf("  %s", line); // 输出如: java/lang/Object.class
    }
    pclose(fp);
    return 0;
}</stdlib.h></stdio.h>

⚠️ 注意事项:

  • 需确保运行环境已安装 JDK(≥9)且 jmod 在 PATH 中;
  • 若需分发独立应用,可静态链接 OpenJDK 的 jmod 源码(openjdk/src/jdk.jmod),但须遵守 GPL v2 with Classpath Exception 许可条款;
  • 绝不建议自行解析 .jmod 结构——OpenJDK 明确声明该格式“不承诺向后兼容”,未来版本可能彻底更换底层容器(如改用 CBOR 或自定义二进制格式)。

2. 次选:绕过魔数头,向 libzip 提供偏移后的数据流

若必须用 libzip 直接读取 ZIP 内容,可手动跳过前 4 字节。一种安全做法是创建内存映射或临时截断副本:

Java Api Extractor
Java Api Extractor

从 Java 项目中提取 Controller 层接口定义为 JSON 数据。

下载
#include <zip.h>
#include <sys>
#include <unistd.h>

struct zip* open_jmod_as_zip(const char* path) {
    int fd = open(path, O_RDONLY);
    if (fd == -1) return NULL;

    // 验证 JMOD 头:必须为 "JM\x01\x00"
    uint8_t header[4];
    if (read(fd, header, 4) != 4 ||
        header[0] != 0x4A || header[1] != 0x4D ||
        header[2] != 0x01 || header[3] != 0x00) {
        close(fd);
        return NULL; // 非法 JMOD 格式
    }

    // 创建从第 4 字节起的内存映射(仅读取 ZIP 部分)
    struct stat st;
    fstat(fd, &st);
    void* zip_data = mmap(NULL, st.st_size - 4, PROT_READ, MAP_PRIVATE, fd, 4);
    close(fd);

    if (zip_data == MAP_FAILED) return NULL;

    // 使用 libzip 的 zip_open_from_source()(需 libzip ≥ 1.8)
    struct zip_source* src = zip_source_buffer_create(zip_data, st.st_size - 4, 0, NULL);
    struct zip* z = zip_open_from_source(src, 0, NULL);
    if (!z) {
        zip_source_free(src);
        munmap(zip_data, st.st_size - 4);
    }
    return z;
}</unistd.h></sys></zip.h>

✅ 优势:零外部依赖,纯 C 实现;
❌ 风险:仍绑定 ZIP 实现细节,且 libzip 版本兼容性需严格测试(旧版不支持 zip_open_from_source)。

3. 不推荐:暴力复制去除头部

简单但低效的做法——将 .jmod 文件复制为临时 ZIP 文件(跳过前 4 字节)再打开:

// (伪代码)仅作示意,生产环境需完善错误处理与临时文件清理
system("dd if=java.base.jmod of=/tmp/tmp.zip bs=1 skip=4 2>/dev/null");
struct zip* z = zip_open("/tmp/tmp.zip", 0, &err);

此方式易引发竞态、磁盘 I/O 开销大,且临时文件权限/清理逻辑复杂,应避免在服务端或高并发场景使用。

? 关键总结

  • .jmod ≠ 标准 ZIP:它是 OpenJDK 的私有封装,JM\x01\x00 头是明确的设计选择,而非 bug;
  • unzip 能打开是因为其实现宽松(只查尾部),而 libzip 等库默认严格(查头部签名);
  • 任何直接解析 .jmod 的 C 代码都存在被未来 JDK 版本静默破坏的风险——OpenJDK 团队已在文档中多次强调此格式“不保证 ABI 兼容性”;
  • 生产级解决方案永远是:通过 jmod 工具桥接,或升级至支持模块化 API 的 JVM(如通过 JNI 调用 java.lang.module.ModuleDescriptor 解析元数据)。

坚持使用官方工具链,是对可维护性与长期稳定性的最大尊重。

Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

java

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

2023.06.15

11597

6

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

2023.07.05

8702

9

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

2023.07.31

7492

8

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.01

1224

3

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.02

988

3

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

1476

5

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

3049

5

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

2023.08.03

20311

3

配置java环境变量
配置java环境变量

配置Java环境变量是为了让操作系统能够识别和使用Java的相关命令和功能。本专题为大家提供配置java环境变量相关文章,帮助大家解决问题。

2023.08.03

1335

8

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习