有没有办法用 JNI 设置 DirectByteBuffer 内存?
Is there a way to set DirectByteBuffer memory with JNI?
出于某种原因,我必须使用 Linux-specific 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);
如何通过给定的ByteBuffer
和JNI
得到char*
?我可以使用 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。
假设您将自己限制在 public 类 和他们的 public 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) , 但在这种情况下,您应该使用 Get
/Release
例程的非 Critical
版本。
话虽如此,将数据一直导入 ByteBuffer
的两个主要替代方法是
如果缓冲区hasArray()
,则通过缓冲区的array()
方法获取上述过程的byte[]
。大功告成。
如果缓冲区没有hasArray()
,或者如果您不想检查,则通过重新实例化它来获得byte[]
,并在通过上述过程,通过缓冲区的批量put(byte[])
或put(byte[], int, int)
方法将内容复制到缓冲区中。显然,这涉及相对于另一个替代方案的额外副本,并且它使用额外的临时对象。
我不建议假设一个特定的具体 ByteBuffer
子类或依赖非 public 方法。如果性能是重中之重,那可能值得考虑,但您似乎说不是。
出于某种原因,我必须使用 Linux-specific 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);
如何通过给定的ByteBuffer
和JNI
得到char*
?我可以使用 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。
假设您将自己限制在 public 类 和他们的 public 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) , 但在这种情况下,您应该使用 Get
/Release
例程的非 Critical
版本。
话虽如此,将数据一直导入 ByteBuffer
的两个主要替代方法是
如果缓冲区
hasArray()
,则通过缓冲区的array()
方法获取上述过程的byte[]
。大功告成。如果缓冲区没有
hasArray()
,或者如果您不想检查,则通过重新实例化它来获得byte[]
,并在通过上述过程,通过缓冲区的批量put(byte[])
或put(byte[], int, int)
方法将内容复制到缓冲区中。显然,这涉及相对于另一个替代方案的额外副本,并且它使用额外的临时对象。
我不建议假设一个特定的具体 ByteBuffer
子类或依赖非 public 方法。如果性能是重中之重,那可能值得考虑,但您似乎说不是。