从Windows 1252到Java的UTF8转换:使用CharsetDecoder / Encoder的空字符

问题描述

| 我知道这是一个非常普遍的问题,但我正在发疯。 我使用以下代码
String ucs2Content = new String(bufferToConvert,inputEncoding);        
        byte[] outputBuf = ucs2Content.getBytes(outputEncoding);        
        return outputBuf;
但是我读到最好使用CharsetDecoder和CharsetEncoder(我的内容中的某些字符可能在目标编码之外)。我刚刚编写了这段代码,但是有一些问题:
// Create the encoder and decoder for Win1252
Charset charsetInput = Charset.forName(inputEncoding);
CharsetDecoder decoder = charsetInput.newDecoder();

Charset charsetoutput = Charset.forName(outputEncoding);
CharsetEncoder encoder = charsetoutput.newEncoder();

// Convert the byte array from starting inputEncoding into UCS2
CharBuffer cbuf = decoder.decode(ByteBuffer.wrap(bufferToConvert));

// Convert the internal UCS2 representation into outputEncoding
ByteBuffer bbuf = encoder.encode(CharBuffer.wrap(cbuf));
return bbuf.array();
的确,此代码一个空字符序列附加到缓冲区中! 有人可以告诉我问题出在哪里吗?我不太擅长Java编码转换。 有没有更好的方法来转换Java编码?     

解决方法

您的问题是,“ 2”返回对用作ByteBuffer的后备存储的数组的直接引用,而不是后备数组有效范围的副本。您必须服从
bbuf.limit()
(就像Peter在他的回答中所做的那样),并且只使用索引
0
bbuf.limit()-1
的数组内容。 支持数组中额外的0值的原因是CharsetEncoder如何创建结果ByteBuffer的一个小缺陷。每个CharsetEncoder具有一个“每个字符平均字节”,对于UCS2编码器来说,这似乎是简单而正确的(每字节2个字节)。遵循此固定值,CharsetEncoder最初会分配一个ByteBuffer,其长度为“字符串长度*每个字符的平均字节数”字节,在这种情况下,例如10个字符长的字符串20个字节。但是,UCS2 CharsetEncoder以BOM(字节顺序标记)开头,该BOM也占用2个字节,因此10个字符中只有9个适合分配的ByteBuffer。 CharsetEncoder检测到溢出并分配一个新的ByteBuffer,其长度为2 * n + 1(n是ByteBuffer的原始长度),在这种情况下为2 * 20 + 1 = 41字节。由于21个新字节中只有2个需要编码其余字符,因此从
bbuf.array()
获得的数组长度为41字节,但是
bbuf.limit()
表示仅实际使用了前22个条目。     ,我不确定如何获得8个字符的序列。尝试这个
String outputEncoding = \"UTF-8\";
Charset charsetOutput = Charset.forName(outputEncoding);
CharsetEncoder encoder = charsetOutput.newEncoder();

// Convert the byte array from starting inputEncoding into UCS2
byte[] bufferToConvert = \"Hello World! £€\".getBytes();
CharBuffer cbuf = decoder.decode(ByteBuffer.wrap(bufferToConvert));

// Convert the internal UCS2 representation into outputEncoding
ByteBuffer bbuf = encoder.encode(CharBuffer.wrap(cbuf));
System.out.println(new String(bbuf.array(),bbuf.limit(),charsetOutput));
版画
Hello World! £€