从ByteBuffer中读取以NUL结尾的字符串

3
我该如何从Java ByteBuffer 中以NUL结尾的UTF-8字符串开始读取,读取位置为ByteBuffer#position()
ByteBuffer b = /* 61 62 63 64 00 31 32 34 00 (hex) */;
String s0 = /* read first string */;
String s1 = /* read second string */;

// `s0` will now contain “ABCD” and `s1` will contain “124”.

我已经尝试使用Charsets.UTF_8.decode(b),但似乎该函数忽略了当前的ByteBuffer位置并读取到缓冲区的末尾。

除了寻找包含0的字节并将缓冲区限制在其中(或将带有字符串的部分复制到单独的缓冲区中),是否有更惯用的方法从字节缓冲区中读取这样的字符串?


3
这不是一个代码编写服务。请发布您自己的努力,并告诉我们您遇到的问题。 - Andrew Henle
对于较低级别的功能,我会研究CharsetDecoder... - Maarten Bodewes
3
将字符读取直到遇到NUL?不清楚问题在哪里。 - user207421
@Jim,是的,但我认为这样做过于复杂了,因为理论上可以使用原始缓冲区。 - jiwopene
@jiwopene:我不太明白你的意思。你确实有多个字符串需要解码,对吧?所以在某个时候,代码需要循环执行。 - Jim
显示剩余2条评论
3个回答

6

“一行代码”的习惯用法我不知道(这并不奇怪,因为以 NUL 结尾的字符串不是 Java 规范的一部分)。

我首先想到的是使用 b.slice().limit(x) 创建一个轻量级视图,只查看所需的字节(比将它们复制到任何位置更好,因为您可能能够直接使用缓冲区进行操作)。

ByteBuffer b = ByteBuffer.wrap(new byte[] {0x61, 0x62, 0x63, 0x64, 0x00, 0x31, 0x32, 0x34, 0x00 });
int i;
while (b.hasRemaining()) {
  ByteBuffer nextString = b.slice(); // View on b with same start position
  for (i = 0; b.hasRemaining() && b.get() != 0x00; i++) {
    // Count to next NUL
  }
  nextString.limit(i); // view now stops before NUL
  CharBuffer s = StandardCharsets.UTF_8.decode(nextString);
  System.out.println(s);
}

1
在Java中,字符\u0000、UTF-8字节0、Unicode代码点U+0是普通字符。因此,读取所有内容(可能会读入一个过大的字节数组),并执行以下操作。
String s = new String(bytes, StandardCharsets.UTF_8);

String[] s0s1 = s.split("\u0000");
String s0 = s0s1[0];
String s1 = s0s1[1];

如果您没有固定的位置并且必须顺序读取每个字节,那么代码将很难看。事实上,C语言的创始人之一曾经称空终止字符串为历史性错误。
相反,为了不为Java字符串生成UTF-8字节0(通常是为了进一步处理作为C / C ++中的空终止字符串),存在编写修改后的UTF-8,也编码0字节的方法。

0

你可以通过使用replacesplit函数来实现。将十六进制字节转换为字符串,并在自定义字符中查找0。然后使用该自定义字符拆分您的字符串。

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

/**
 * Created by Administrator on 8/25/2020.
 */
public class Jtest {
    public static void main(String[] args) {
        //ByteBuffer b = /* 61 62 63 64 00 31 32 34 00 (hex) */;
        ByteBuffer b = ByteBuffer.allocate(10);

        b.put((byte)0x61);
        b.put((byte)0x62);
        b.put((byte)0x63);
        b.put((byte)0x64);
        b.put((byte)0x00);
        b.put((byte)0x31);
        b.put((byte)0x32);
        b.put((byte)0x34);
        b.put((byte)0x00);
        b.rewind();

        String s0;
        String s1;

        // print the ByteBuffer
        System.out.println("Original ByteBuffer:  "
                + Arrays.toString(b.array()));

        // `s0` will now contain “ABCD” and `s1` will contain “124”.
        String s = StandardCharsets.UTF_8.decode(b).toString();
        String ss = s.replace((char)0,';');
        String[] words = ss.split(";");
        for(int i=0; i < words.length; i++) {
            System.out.println(" Word " + i + " = " +words[i]);
        }

    }
}

我相信你可以更高效地完成它,去掉替换操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接