如何使用BOM对UTF-16LE字节数组进行编码/解码?

Jar*_*aus 22 java unicode byte-order-mark utf-16

我需要对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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

public String(byte[] bytes,
              int offset,
              int length,
              String charsetName)
Run Code Online (Sandbox Code Playgroud)

McD*_*ell 28

"UTF-16"字符集名称将始终使用BOM进行编码,并使用大/小字节顺序解码数据,但"UnicodeBig"和"UnicodeLittle"对于按特定字节顺序进行编码非常有用.使用UTF-16LE或UTF-16BE无需BOM - 请参阅此文章,了解如何使用"\ uFEFF"手动处理BOM.请参阅此处了解charset字符串名称或(最好)Charset类的规范命名.另请注意,绝对需要仅支持有限的编码子集.

  • 重申一下:"UnicodeLittle"(又名"x-UTF-16LE-BOM")会将文件写成带有BOM的UTF-16 little-endian.这应该是写入文件的首选方法,但它似乎只有Java 6(JDK 1.6)才可用.对于READING,你应该坚持使用"UTF-16". (6认同)
  • 我完全不会惊讶于Microsoft定义一种格式,它希望UTF-16LE BOM开始一个文件,如果文件以UTF-8 BOM或UTF-16BE BOM开头,则不会表现.我完全不会感到惊讶,因为这正是我在excel加载CSV文件时观察到的行为 - 如果文件以UTF-16LE BOM开头,那么它以UTF-16LE加载数据并期望列之间的标签.任何其他字符序列,它使用","或";"加载某些本地字符集中的数据 列之间(依赖于语言环境!) (4认同)

Yis*_*hai 7

这就是你在nio中的表现:

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

它当然应该更快,但我不知道它在幕后制作了多少阵列,但我对API的要点的理解是它应该最小化它.


Dan*_*tin 6

首先,对于解码,您可以使用字符集"UTF-16"; 自动检测初始BOM.对于UTF-16BE编码,你也可以使用"UTF-16"字符集 - 它会写出一个合适的BOM,然后输出大端的东西.

对于使用BOM编码到小端,我不认为你当前的代码太糟糕了,即使是双重分配(除非你的字符串真的是怪异的).如果它们不是处理字节数组而是处理java.nio ByteBuffer,并且使用java.nio.charset.CharsetEncoder类,那么您可能想要做什么.(你可以从Charset.forName("UTF-16LE").newEncoder()获得.