簡體   English   中英

如何使用BOM對UTF-16LE字節數組進行編碼/解碼?

[英]How do I encode/decode UTF-16LE byte arrays with a BOM?

我需要在java.lang.String對UTF-16字節數組進行編碼/解碼。 字節數組是通過字節順序標記(BOM)給我的,我需要使用BOM編碼字節數組。

另外,由於我正在與Microsoft客戶端/服務器打交道,因此我希望以小字節序(與LE BOM一起)發出編碼,以避免任何誤解。 我確實意識到,使用BOM可以在大端模式下工作,但是我不想在Windows世界上游。

舉例來說,以下是一種方法,該方法將java.lang.String編碼為帶有BOM的little endian中的UTF-16

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編碼為小端的編碼,我認為即使使用雙重分配,您當前的代碼也不會太糟糕(除非您的字符串確實很可怕)。 如果不是這樣,您可能想做的不是處理字節數組,而是處理java.nio ByteBuffer,並使用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沒有用於帶有BOM的UTF-16LE的內置編碼器。 因此,您必須推出自己的實現。

我最終得到的是:

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 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM