首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ByteBuffer、CharBuffer、String和Charset

ByteBuffer、CharBuffer、String和Charset
EN

Stack Overflow用户
提问于 2014-06-29 23:41:25
回答 3查看 15.3K关注 0票数 7

我试图根据字符集来整理字符、它们在字节序列中的表示,以及如何在Java中从一个字符集转换到另一个字符集。我有一些困难。

例如,

代码语言:javascript
复制
ByteBuffer bybf = ByteBuffer.wrap("Olé".getBytes());

我的理解是:

  • 字符串总是以UTF-16字节顺序存储在Java中(每个字符2字节,大端)
  • getBytes()结果是相同的UTF-16字节序列。
  • wrap()维护此序列
  • 因此,bybf是字符串Olé的UTF-16大端表示形式。

因此,在本代码中:

代码语言:javascript
复制
Charset utf16 = Charset.forName("UTF-16");  
CharBuffer chbf = utf16.decode(bybf);  
System.out.println(chbf);  

decode()应该

  • bybf解释为UTF-16字符串表示。
  • 将其“转换”为原始字符串Olé

实际上,不应该改变任何字节,因为所有东西都存储在UTF-16中,而UTF-16 Charset应该是一种“中性运算符”。然而,结果被打印为:

代码语言:javascript
复制
??

,怎么可能?

附加问题:为了正确转换,Charset.decode(ByteBuffer bb)似乎需要bb是一个字符串的UTF-16大字节序列图像。是对的吗?

编辑:根据提供的答案,我做了一些测试来打印ByteBuffer内容和通过解码得到的chars。使用="Olé".getBytes(charsetName)编码的字节被打印在组的第一行上,另一行(S)是通过用不同的Charset#decode(ByteBuffer)对字节进行解码而得到的字符串。

我还确认,在Windows7计算机上将字符串存储到byte[]中的默认编码是windows-1252 (除非字符串包含需要UTF-8的字符)。

代码语言:javascript
复制
Default VM encoding: windows-1252  
Sample string: "Olé"  


  getBytes() no CS provided : 79 108 233  <-- default (windows-1252), 1 byte per char
     Decoded as windows-1252: Olé         <-- using the same CS than getBytes()
           Decoded as UTF-16: ??          <-- using another CS (doesn't work indeed)

  getBytes with windows-1252: 79 108 233  <-- same than getBytes()
     Decoded as windows-1252: Olé

         getBytes with UTF-8: 79 108 195 169  <-- 'é' in UTF-8 use 2 bytes
            Decoded as UTF-8: Olé

        getBytes with UTF-16: 254 255 0 79 0 108 0 233 <-- each char uses 2 bytes with UTF-16
           Decoded as UTF-16: Olé                          (254-255 is an encoding tag)
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-06-30 01:54:28

你基本上是对的。

java中的本机字符表示形式是UTF-16。但是,当将字符转换为字节时,您可以指定正在使用的字符集,或者系统使用它的默认设置,这通常是UTF-8。这将产生有趣的结果,如果你是混合和匹配。

对于我的系统,如下所示

代码语言:javascript
复制
System.out.println(Charset.defaultCharset().name());
ByteBuffer bybf = ByteBuffer.wrap("Olé".getBytes());
Charset utf16 = Charset.forName("UTF-16");
CharBuffer chbf = utf16.decode(bybf);
System.out.println(chbf);
bybf = ByteBuffer.wrap("Olé".getBytes(utf16));
chbf = utf16.decode(bybf);
System.out.println(chbf);

产生

UTF-8

佬쎩

欧蕾

因此,只有当UTF-16是默认字符集时,此部分才是正确的。

getBytes() result is this same UTF-16 byte sequence.

因此,要么始终指定您正在使用的字符集,这是最安全的,因为您将始终知道发生了什么,或者始终使用默认值。

票数 8
EN

Stack Overflow用户

发布于 2014-06-30 06:04:20

字符串总是以UTF-16字节顺序存储在Java中(每个字符2字节,大端)

是。

getBytes()结果是相同的UTF-16字节序列

不是的。它将UTF-16字符编码到平台默认字符集中,不管是什么。不赞成。

wrap()维护此序列

wrap()维护一切。

因此,bybf是字符串Olé的UTF-16大端表示形式。

不是的。它封装了平台原始字符串的默认编码。

解码()应该

  • 将bybf解释为UTF-16字符串表示形式。

不,看上面。

  • “转换”为原始字符串Olé。

除非平台的默认编码是"UTF-16“。

票数 7
EN

Stack Overflow用户

发布于 2015-07-08 07:16:42

对于双字节字符集编码的数据,我也遇到了几乎相同的问题。上面的答案3已经包含了你应该注意的关键问题。

  1. 为源编码定义字符集。
  2. 仅在与本地系统编码不同的情况下为目标编码定义字符集。

以下代码工作

代码语言:javascript
复制
public static String convertUTF16ToString(byte[] doc)
{
    final Charset doublebyte = StandardCharsets.UTF_16;
    // Don't need this because it is my local (system default).  
    //final Charset ansiCharset = StandardCharsets.ISO_8859_1;

    final CharBuffer encoded = doublebyte.decode(ByteBuffer.wrap(doc));
    StringBuffer sb = new StringBuffer(encoded);
    return sb.toString();        
}

用您喜欢的编码替换系统默认设置。

代码语言:javascript
复制
public static String convertUTF16ToUTF8(byte[] doc)
{
    final Charset doublebyte = StandardCharsets.UTF_16; 
    final Charset utfCharset = StandardCharsets.UTF_8; 
    final Charset ansiCharset = StandardCharsets.ISO_8859_1;

    final CharBuffer encoded1 = doublebyte.decode(ByteBuffer.wrap(doc));
    StringBuffer sb = new StringBuffer(encoded1);
    final byte[] result = ansiCharset.encode(encoded1).array();
    // alternative to utf-8
    //final byte[] result = utfCharset.encode(encoded1).array();

    return new String(result);        
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24481238

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档