我需要对 UTF-16 字节数组进行编码/解码 java.lang.String. 。字节数组是通过一个给我的 字节顺序标记 (BOM), ,并且我需要使用 BOM 对字节数组进行编码。

另外,因为我正在处理 Microsoft 客户端/服务器,所以我想以小尾数法(以及 LE BOM)发出编码以避免任何误解。我确实意识到,对于 BOM,它应该以大端方式工作,但我不想在 Windows 世界中逆流而上。

作为一个例子,这是一个编码的方法 java.lang.String 作为 UTF-16 带有 BOM 的小端字节序:

public static byte[] encodeString(String message) {

    byte[] tmp = null;
    try {
        tmp = message.getBytes("UTF-16LE");
    } catch(UnsupportedEncodingException e) {
        // should not possible
        AssertionError ae =
        new AssertionError("Could not encode UTF-16LE");
        ae.initCause(e);
        throw ae;
    }

    // use brute force method to add BOM
    byte[] utf16lemessage = new byte[2 + tmp.length];
    utf16lemessage[0] = (byte)0xFF;
    utf16lemessage[1] = (byte)0xFE;
    System.arraycopy(tmp, 0,
                     utf16lemessage, 2,
                     tmp.length);
    return utf16lemessage;
}

在 Java 中执行此操作的最佳方法是什么?理想情况下,我想避免将整个字节数组复制到一个新的字节数组中,该数组在开头分配了两个额外的字节。

解码这样的字符串也是如此,但是使用 java.lang.String 构造函数:

public String(byte[] bytes,
              int offset,
              int length,
              String charsetName)
有帮助吗?

解决方案

“UTF-16”字符集名称将始终使用 BOM 进行编码,并使用大/小字节序对数据进行解码,但“UnicodeBig”和“UnicodeLittle”对于以特定字节顺序进行编码非常有用。对于无 BOM 使用 UTF-16LE 或 UTF-16BE - 看到这个帖子 了解如何使用“\uFEFF”手动处理 BOM。看 这里 用于字符集字符串名称的规范命名或(最好) 字符集 班级。另请注意,只有一个 有限的编码子集 是绝对需要支持的。

其他提示

这是你如何在NIO做到这一点:

    return Charset.forName("UTF-16LE").encode(message)
            .put(0, (byte) 0xFF)
            .put(1, (byte) 0xFE)
            .array();

这当然应该是快,但我不知道有多少阵列使得在幕后,但是我的API点的理解是,它应该尽量减少。

首先,用于解码可使用的字符集“UTF-16”;自动检测的初始BOM。对于编码UTF-16BE,您还可以使用“UTF-16”字符集 - 那会写一个正确的BOM,然后输出大端东西

有关编码为小端与BOM,我不认为你当前的代码是太糟糕了,即使有双重分配(除非你的字符串是真正可怕的)。你可能会想,如果他们不处理的字节数组,而是一个ByteBuffer的java.nio中,并使用java.nio.charset.CharsetEncoder类的事情。 (你可以从Charset.forName( “UTF-16LE”)。newEncoder())。

    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(string.length() * 2 + 2);
    byteArrayOutputStream.write(new byte[]{(byte)0xFF,(byte)0xFE});
    byteArrayOutputStream.write(string.getBytes("UTF-16LE"));
    return byteArrayOutputStream.toByteArray();

编辑:重读你的问题,我看你宁愿避免双重数组分配完全。不幸的是,API不给你的是,据我所知。 (有一种方法,但它已被弃用,则不能指定与它的编码)。

我写上面之前我看到你的评论,我想用NIO类的答案是正确的轨道上。我看着这一点,但我不熟悉不够用API知道了手如何弄完。

这是一个老问题了,不过,我找不到我的情况可以接受的答案。基本上,Java没有为UTF-16LE以BOM内置编码器。所以,你必须推出自己的实现。

这是我结束了:

private byte[] encodeUTF16LEWithBOM(final String s) {
    ByteBuffer content = Charset.forName("UTF-16LE").encode(s);
    byte[] bom = { (byte) 0xff, (byte) 0xfe };
    return ByteBuffer.allocate(content.capacity() + bom.length).put(bom).put(content).array();
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top