【问题标题】:Java bug? Why extra zero byte in utf8 encoding?爪哇错误?为什么在 utf8 编码中有额外的零字节?
【发布时间】:2012-07-03 21:31:20
【问题描述】:

以下代码

public class CharsetProblem {
public static void main(String[] args) {
    //String str = "aaaaaaaaa";
    String str = "aaaaaaaaaa";
    Charset cs1 = Charset.forName("ASCII");
    Charset cs2 = Charset.forName("utf8");

    System.out.println(toHex(cs1.encode(str).array()));
    System.out.println(toHex(cs2.encode(str).array()));

}

public static String toHex(byte[] outputBytes) {

    StringBuilder builder = new StringBuilder();

    for(int i=0; i<outputBytes.length; ++i) {
        builder.append(String.format("%02x", outputBytes[i]));
    }

    return builder.toString();
}
}

返回

61616161616161616161
6161616161616161616100

即utf8 编码返回多余的字节。如果我们采用更少的 a-s,那么我们将没有多余的字节。如果我们采用更多的 a-s,我们可以获得越来越多的多余字节。

为什么?

如何解决这个问题?

【问题讨论】:

    标签: java utf-8 character-encoding


    【解决方案1】:

    您不能只获取支持数组并使用它。 ByteBuffers 有一个capacity, position and a limit

    System.out.println(cs1.encode(str).remaining());
    System.out.println(cs2.encode(str).remaining());
    

    产生:

    10
    10
    

    试试这个:

    public static void main(String[] args) {
      //String str = "aaaaaaaaa";
      String str = "aaaaaaaaaa";
      Charset cs1 = Charset.forName("ASCII");
      Charset cs2 = Charset.forName("utf8");
    
      System.out.println(toHex(cs1.encode(str)));
      System.out.println(toHex(cs2.encode(str)));
    }
    
    public static String toHex(ByteBuffer buff) {
      StringBuilder builder = new StringBuilder();
      while (buff.remaining() > 0) {
        builder.append(String.format("%02x", buff.get()));
      }
      return builder.toString();
    }
    

    它产生预期的:

    61616161616161616161
    61616161616161616161
    

    【讨论】:

      【解决方案2】:

      您假设 ByteBuffer 的后备数组恰好是容纳内容的正确大小,但不一定。事实上,内容甚至不需要从数组的第一个字节开始!研究ByteBuffer的API,你就会明白是怎么回事:内容从arrayOffset()返回的值开始,到limit()返回的结束。

      【讨论】:

        【解决方案3】:

        已经给出了答案,但是当我遇到同样的问题时,我认为提供更多细节可能会很有用:

        调用cs1.encode(str).array()cs2.encode(str).array()返回的字节数组返回对当时分配给ByteBuffer的整个数组的引用。阵列的容量可能大于实际使用的容量。要仅检索使用过的部分,您应该执行以下操作:

        ByteBuffer bf1 = cs1.encode(str);
        ByteBuffer bf2 = cs2.encode(str);
        System.out.println(toHex(Arrays.copyOf(bf1.array(), bf1.limit())));
        System.out.println(toHex(Arrays.copyOf(bf2.array(), bf2.limit())));
        

        这会产生您期望的结果。

        【讨论】:

          猜你喜欢
          • 2019-09-21
          • 2016-08-12
          • 2022-07-06
          • 1970-01-01
          • 2015-04-23
          • 1970-01-01
          • 1970-01-01
          • 2011-06-24
          相关资源
          最近更新 更多