给定的
test.h看起来像:
#include <stdio.h>inline void setLogFile(FILE *fd) { fprintf(fd, "Testn"); fflush(fd);}我可以看到您可能会选择使用三种方法来包装此函数:
方法1-String从Java传递a :
向Java公开一个函数,该函数期望文件名以而String不是a形式传递FILE*:
%module method1%{#include "test.h"%}%inline %{void setLogFile(const char *fn) { FILE *f = fopen(fn, "w"); setLogFile(f);}%}这用于%inline指示SWIG在定义该函数的同时包装该函数。如果仍然使用,%include “test.h”则可能要对SWIG隐藏原始版本。
方法2-包装更多stdio.h:
包裹不止setLogFile,包裹的东西喜欢fopen,fmemopen等适当的。(我个人不太喜欢这种解决方案,因此我没有举一个例子)
方法3-公开一个带有以下内容的Java接口FileOutputStream:
%module method3%{#include "test.h"#include <cassert>%}// 3:%typemap(jni) FILE *fd "jobject"// 1:%typemap(jstype) FILE *fd "java.io.FileOutputStream"// 2:%typemap(jtype) FILE *fd "java.io.FileDescriptor"// 4:%typemap(in) (FILE *fd) { jfieldID field_fd; jclass class_fdesc; int rawfd; class_fdesc = jenv->FindClass("java/io/FileDescriptor"); assert(class_fdesc); field_fd = jenv->GetFieldID(class_fdesc, "fd", "I"); assert(field_fd); rawfd = jenv->GetIntField($input, field_fd); $1 = fdopen(rawfd, "w"); // Add some pre to throw a Java exception if $1 is NULL (i.e. error)}// 5: %typemap(javain, pre=" retainFD = $javainput;", throws="java.io.IOException") FILE *fd "$javainput.getFD()"// 6:%pragma(java) modulepre=%{ private static java.io.FileOutputStream retainFD;%}%include "test.h"这将执行以下操作:
- 我们希望输入到模块的实际公共部分
java.io.FileOutputStream
。 - 但是,JNI代码的Java端将改为使用
java.io.FileDescriptor
。 - JNI代码的C ++端将其视为 jobject
- 在C ++方面,我们将做一些有点邪恶的事情-读取类中的私有int字段
FileDescriptor
(请参见此处)。这可能不是便携式和阅读类私处通常被认为是不好的,但它使我们能够得到的东西我们可以通过fdopen()得到一个FILE*“真正”的号召 - 通常,此类型图接受
FileOutputStream
并对其进行调用getFD()以获取其FileDescriptor
对象。它还添加了一个异常规范以匹配getFD()
并执行另一个功能,这是下一点的一部分 - 我们需要确保Java不会垃圾回收并完成
FileOutputStream
,这将关闭文件句柄并使我们的无效FILE*。我们通过FileOutputStream
在private static
变量中引用我们来实现。在pre=”…以前的类型映射的原因最近的一次被保留,直到我们切换到另一个。(如果我们打电话setLogFile
两次,那没关系,实际上释放我们对前一个的引用是件好事FileOutputStream
)



