在 Java 中将 ByteBuffer 转换为字符串

Posted

技术标签:

【中文标题】在 Java 中将 ByteBuffer 转换为字符串【英文标题】:Convert ByteBuffer to String in Java 【发布时间】:2015-03-22 03:36:45 【问题描述】:

我有一个来自ByteBufferbyte[] bytes,其中包含一个数据包。我想将数据包放入String

目前我有以下

    byte[] bytes = packet.array();
    System.out.println("Packet String:" + new String(bytes));

但我最终得到以下输出

Packet String:E����<Ҧ@��@�.
03-22 04:30:28.187   9296-10152/willem.com.*** I/System.out﹕ ����J�j���k�:����������9�������
03-22 04:30:28.197   9296-10152/willem.com.*** I/System.out﹕ ��&�4��������ddrarpa��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

我试过这样编码

System.out.println("Packet String:" + new String(bytes, Charset.forName("UTF-8")));

但这不是正确的字符集。谁能告诉我是什么?

【问题讨论】:

没有人 可以告诉您您自己的文件的正确字符集是什么。只有您或编写它的软件才能产生这种效果。 以下reference on JAVA NIO ByteBuffer Basic Usage 解释了您阅读garbaje 的原因。 【参考方案1】:

您需要使用缓冲区的位置和限制来确定要读取的字节数。

// ...populate the buffer...
buffer.flip(); // flip the buffer for reading
byte[] bytes = new byte[buffer.remaining()]; // create a byte array the length of the number of bytes written to the buffer
buffer.get(bytes); // read the bytes that were written
String packet = new String(bytes);

在我看来,你根本不应该使用支持array();这是不好的做法。直接字节缓冲区(由ByteBuffer.allocateDirect() 创建的没有后备数组,并且在您尝试调用ByteBuffer.array() 时会抛出异常。因此,为了可移植性,您应该尝试使用标准缓冲区get 和@ 987654326@ 方法。当然,如果你真的想使用数组,你可以使用ByteBuffer.hasArray() 来检查缓冲区是否有后备数组。

【讨论】:

然后我得到一个java.nio.BufferUnderflowException 并且字符串仍然没有意义 听起来您可能需要先致电flip。写入缓冲区时,在再次读取之前,您通常需要调用flip 来重置位置和限制。 flip 会将位置设置为0,并将限制设置为当前position,从而使remaining 等于写入缓冲区的字节数。 我需要在哪里调用它? 通常你应该在写入缓冲区之后调用flipflip 用于在缓冲区的写入和读取之间切换。写入字节时,缓冲区的位置会提前。为了从中读取,您需要 flip 缓冲区从头开始读取。 ByteBuffer API 有点混乱,可能需要一段时间才能理解。 我会说你需要调用flip()之前任何读取缓冲区,然后立即调用compact()。保持缓冲区始终准备好写入(和读取)是最简单的,并且只让它们处于翻转状态的时间越短越好。【参考方案2】:

关于从位置到极限的设置范围的答案在一般情况下是不正确的。当缓冲区已被部分消耗或引用数组的一部分时(您可以ByteBuffer.wrap 给定偏移量的数组,不一定从头开始),我们必须在计算中考虑到这一点。这是在所有情况下都适用于缓冲区的通用解决方案(不包括编码):

if (myByteBuffer.hasArray()) 
    return new String(myByteBuffer.array(),
        myByteBuffer.arrayOffset() + myByteBuffer.position(),
        myByteBuffer.remaining());
 else 
    final byte[] b = new byte[myByteBuffer.remaining()];
    myByteBuffer.duplicate().get(b);
    return new String(b);

有关编码的问题,请参阅 Andy Thomas 的回答。

【讨论】:

这是对我有用的解决方案。谢谢。【参考方案3】:

您忽略了缓冲区的limit。你应该flip()缓冲区,然后调用

new String(buffer.array(), 0, buffer.position())

然后重置它。

但您确实应该使用Charset 解码器来为此生成CharBuffer。至少您应该为String 构造函数指定一个字符集。

【讨论】:

您创建它,调用CharsetDecoder.decode(ByteBuffer) 生成CharBuffer,,然后将其直接转换为String. 但我不知道该使用什么字符集,我该如何找到? 了解任意字节数组的字符集并不是一个好方法。你需要提前知道那件事。有一些像 Apache Tika 这样的库可以提供字符集的猜测,但与任何格式猜测一样,这是一门不完善的科学。 应该指定编码,但更严重的是 buffer.limit() 是一个偏移量,而不是长度。构造函数希望使用字节长度。 You should flip() the buffer, then call 这会将位置重置为零。因此,new String(buffer.array(), 0, buffer.position()) 将不起作用。【参考方案4】:

ByteBuffer 数据 = ...

新字符串(data.array() , "UTF-8");

【讨论】:

以上是关于在 Java 中将 ByteBuffer 转换为字符串的主要内容,如果未能解决你的问题,请参考以下文章

在 Java 中将 ByteBuffer 转换为字符串

如何在 JNI 中将 char[] 转换为 ByteBuffer?

如何在 Kotlin 中将数据类转换为 ByteBuffer?

在 Java 中转换 ByteBuffer 和 String 的问题

Java:转换 ByteBuffer 多维数组

Java:将 String 与 ByteBuffer 相互转换以及相关问题