由于某种原因,我必须使用特定于Linux的API,该API当前无法直接从JVM访问,并且需要设计一种接受ByteBuffer
的方法(这绝对不是出于性能原因)。这是它的样子:
//I need to call device-specific ioctl here
//and fill the ByteBuffer
public static native long putIntoByteBuffer(int fd, ByteBuffer buf);
生成的头文件是
JNIEXPORT jlong JNICALL Java_net_abcomm_PlatformSpecific_putIntoByteBuffer
(JNIEnv *, jclass, jint, jobject);
如何使用char*
通过给定的ByteBuffer
获得JNI
?我可以使用DirectBuffer
,但随后我将仅限于DirectBuffer
,并且会生成以下警告:
warning: DirectBuffer is internal proprietary API and may be removed in a
future release
import sun.nio.ch.DirectBuffer;
也有GetDirectBufferAddress
返回void*
,但仅限于DirectBuffer
s。
答案 0 :(得分:3)
假设您将自己限制在公共类及其公共API上,则有两种相对有效的替代方法可以解决此问题,但是它们的共同点在于它们依赖于将数据放入Java byte[]
中。那并不难:
/* error checks omitted for brevity; these are *not* optional */
char *cBytes = /* ... */;
size_t numCBytes = /* ... */;
jbyteArray javaBytes = /* ... */;
jsize numBytes = (*env)->GetArrayLength(env, javaBytes);
jbyte *bytes = (*env)->GetPrimitiveArrayCritical(env, javaBytes, NULL);
/* It is pretty safe to assume that jbyte is a character type, such as signed
char, in any C implementation that supports the JNI at all */
/* Assumes numCBytes <= numBytes; adjust as necessary if that may not be true: */
memcpy(bytes, cBytes, numCBytes);
(*env)->ReleasePrimitiveArrayCritical(env, javaBytes, bytes, 0);
请注意,如果JNI函数执行某种I / O来获取字节,则它可能能够将它们直接读取到bytes
中(取决于本机要求,而不是JNI),但是情况下,您应该使用Critical
/ Get
例程的非Release
版本。
话虽如此,将数据一直获取到ByteBuffer
的两个主要选择是
如果缓冲区为hasArray()
,则通过缓冲区的byte[]
方法获得上述过程的array()
。完成并完成。
如果缓冲区没有hasArray()
,或者您不想检查,则通过重新实例化获取byte[]
,并通过上述过程加载后,进行复制通过缓冲区的批量put(byte[])
或put(byte[], int, int)
方法将内容放入缓冲区。显然,这涉及到相对于其他选择的额外副本,并且它使用了额外的临时对象。
我不建议您假设特定的具体ByteBuffer
子类或依赖于非公共方法。如果性能是当务之急,那也许值得考虑,但是您似乎不是这样。