JNA调用Native函数无法获取嵌套结构数据求助
问题诊断与解决方法
核心问题分析
你的代码存在三个关键问题,导致file.src始终为null:
- 文件名缺少null终止符:C语言的
char*字符串必须以\0结尾,你用ByteBuffer传递路径时只写入了路径字节,没有添加终止符,Native函数无法正确识别文件名,导致文件加载失败。 - 结构参数传递方式错误:Native函数要求传入
MyLoadFile*(结构指针),你直接传递MyLoadFile实例时,JNA默认按值传递(ByValue),而非引用传递,Native函数无法修改你创建的Java结构对象。 - 未同步Native内存到Java对象:即使Native函数修改了结构内存,JNA不会自动将更新同步到Java对象,需要手动调用
read()方法刷新数据。
分步解决
1. 修正文件名传递
直接使用String传递文件名,JNA会自动处理char*的转换和null终止符,比手动操作ByteBuffer更可靠:
String fName = "D:/test/file";
2. 调整JNA函数定义
将第二个参数改为MyLoadFile.ByReference,明确告诉JNA传递结构的指针:
int LoadFile(String fname, MyLoadFile.ByReference logfile, int reset);
3. 修正调用逻辑
实例化MyLoadFile.ByReference,调用函数后手动调用read()同步内存:
MyLoadFile.ByReference file = new MyLoadFile.ByReference(); int retCode = MyLibrary.LoadFile("D:/test/file", file, 0); System.out.println("Ret code: " + retCode); // 同步Native修改后的内存到Java对象 file.read(); // 现在可以访问file.src if (file.src != null) { // 若需要访问Src的内容,同样要调用src.read() file.src.read(); // 比如获取FileId: String fileId = file.src.FileId.getString(0); System.out.println("FileId: " + fileId); }
4. 额外注意事项
- 如果你坚持使用
ByteBuffer传递文件名,必须手动添加null终止符:byte[] bytes = "D:/test/file\0".getBytes(StandardCharsets.US_ASCII); ByteBuffer fName = ByteBuffer.allocateDirect(bytes.length); fName.put(bytes); fName.flip(); - 对于嵌套的
Src结构,当file.src不为null时,需要调用file.src.read()才能获取其内部字段的值,因为Src.ByReference本质是指针,JNA不会自动读取指向的内存内容。
完整修正后的代码示例
JNA函数接口
int LoadFile(String fname, MyLoadFile.ByReference logfile, int reset);
调用代码
MyLoadFile.ByReference file = new MyLoadFile.ByReference(); int retCode = MyLibrary.LoadFile("D:/test/file", file, 0); System.out.println("Ret code: " + retCode); // 同步结构数据 file.read(); if (file.src != null) { file.src.read(); // 读取FileId String fileId = file.src.FileId.getString(0); System.out.println("FileId: " + fileId); // 读取Version数组 for (int i = 0; i < file.src.Version.length; i++) { System.out.println("Version[" + i + "]: " + file.src.Version[i].longValue()); } }
内容的提问来源于stack exchange,提问作者Andrey Vladimirovich
相关产品推荐
相关产品推荐

