直接字节缓冲区

Posted

技术标签:

【中文标题】直接字节缓冲区【英文标题】:Direct ByteBuffer 【发布时间】:2014-03-15 11:25:14 【问题描述】:

我正在使用 JNI 测试直接 ByteBuffer(java.nio.ByteBuffer)。所以下面的代码试图:

    在 Java 中将值直接放入 ByteBuffer 在 C++ 中更改值 在 Java 中获取值

我想知道我到底哪里做错了? C++ 代码设法从 Java 中获取数据,但 C++ 中的更改并没有反映在 Java 中。

这是我在 java 上所做的:

public static void main(String[] args)
    ByteBuffer bb = ByteBuffer.allocateDirect(3);
    byte[] b = 122,121,120;
    System.out.println("1: " + new String(b));
    bb.put(b);

    new JNI.process(bb);

    byte[] c = new byte[3];
    c[0] = bb.get();
    System.out.println("4: " + new String(c));

这是我在 JNI 函数上所做的:

JNIEXPORT void JNICALL Java_MarsJNI_mapreduce
  (JNIEnv *env, jobject thisObj, jobject output)
    char *out = (char*)env->GetDirectBufferAddress(output);
    printf("2: %s\n", out);
    out = "ABC";
    printf("3: %s\n", out);

我得到的结果是:

1: zyx
2: zyx
3: ABC
Exception in thread "main" java.nio.BufferUnderflowException
    at java.nio.Buffer.nextGetIndex(Buffer.java:474)
    at java.nio.DirectByteBuffer.get(DirectByteBuffer.java:208)
    at MarsJNI.main(MarsJNI.java:21)

【问题讨论】:

除了@TedBigham 提到的,你的问题是你的修改永远不会进入原始数组 @fge 你指的是 out = "ABC";在 C++ 代码中? @TedBigham 确实是的 我也怀疑过,但我的 C++ 相当生锈。我认为他需要做一个 strcpyn。 @TedBigham 应该是 strncpy() 但这确实是问题的本质 【参考方案1】:

第一个问题:见@TedBigham 的回答。你也可以使用buf.rewind()

第二个问题:您只将缓冲区的第一个字节复制到c,而不是整个缓冲区。做:

byte[] c = new byte[3];
bb.rewind();
bb.put(c);
System.out.println("4: " + new String(c));

第三个问题:你的 C++ 代码:

char *out = (char*)env->GetDirectBufferAddress(output);
// ...
out = "ABC";

但是你在这里做的是创建 'A', 'B', 'C', 0 并将out 分配给它;您实际上并没有修改缓冲区的内容。你应该这样做:

memcpy(out, "ABC", 3);

第四个问题:当你从一个byte[]创建一个String时,你应该指定编码:

new String(c, StandardCharsets.UTF_8);

【讨论】:

哇,你从一开始就完全了解我。谢谢! Welcome ;) 我还发现了另一个问题……不过,这个问题可能很难处理。我不知道与 Java 的 char 等效的 C++ 是什么(wchar_t?),也不知道它如何处理语言环境。 知道等价是否有帮助的任何特定场景?我以为通过JNI,我们不应该担心这个? 视情况而定;您打算操作文本还是纯字节?如果您操纵文本,是的,这应该从一开始就担心。【参考方案2】:

我认为你需要在调用 bb.get() 之前调用 bb.position(0)

【讨论】:

是的,这是一个问题;不过还有一个

以上是关于直接字节缓冲区的主要内容,如果未能解决你的问题,请参考以下文章

NIO直接缓冲区和非直接缓冲区

Java NIO -- 直接缓冲区与非直接缓冲区

缓冲流的使用:BufferedInputStreamBufferedOutputStreamBufferedReaderBufferedWriter

有没有办法在 Java 中压缩字节缓冲区?

Java NIO之缓冲区

从固定大小的字节缓冲区的连续块中解析 protobuf 消息序列