您的位置:首页 > Web前端

解码(ByteBuffer): CharsetDecoder.decode() 与 Charset.decode() 的不同

2015-06-17 14:36 531 查看
今天测试的时候发现一个问题:

ByteBuffer inputBuffer = ByteBuffer.allocate(1024);

StringBuilder inputData = new StringBuilder(256);

int size = sChannel.read(inputBuffer);

Charset charset = Charset.forName("utf-8");
CharsetDecoder decoder = charset.newDecoder();

try
{

//如果用utf-8解码,抛java.nio.charset.MalformedInputException:Malformed input length is 1

//如果用gbk解码,抛 java.nio.charset.MalformedInputException:Malformed input length is 2

//抛异常的几率在5%左右,也就是说并不是每次都会抛异常
inputData.append(decoder.decode(inputBuffer));

}
catch (CharacterCodingException err)
{
System.err.println("CharacterCodingException:\n" + new String(inputBuffer.array()));
err.printStackTrace();
}

到百度搜索了一下,找到一篇:http://topic.csdn.net/u/20100310/17/4cf1c1a5-b01c-4774-a803-81ee245ae0eb.html

主要内容:

1. 这种现象是很正常的,由于网络上是一bit为单位传输,而TCP层上送的数据是以字节为单位,虽然NIO是以块为单位操作的,但是应用层处理时还是得以字节为单位处理。但是你使用的应该是ByteBuffer的派生类,(猜测是CharBuffer)它是以两个字节为单位处理报文的,因此很容易出现楼主的问题。

解决方案:
在处理数据之前,先判断ByteBuffer中的字节数,如果为奇数,则直接return false;不进行处理,等下一个消息来到时统一处理(注:可以这样做的原因是,这种现象是由于传输层上送的数据非完整应用层包) 2. 因为在GBK中字母占1byte汉字占2byte。ByteBuffer如果设置长度为偶数时,如果有奇数个字母那么最后的byte就是汉字的一部分,转码的时候就会出错。Bytebuffer设为奇数正好相反。可以判断ByteBuffer.get(index)大于0小于127的个数,然后确定最后一位是否要放到下次读入的第一位 3. 帖子的答案:“你是怎么处理数据包的,有处理粘包吗” ,粘包为何物? 再搜索,又找到一篇:http://www.blogjava.net/easywu/archive/2009/06/04/280100.html
如果直接使用Charset.decode()方法,则不会出现这样的错误: private final static Charset charset = Charset.forName("UTF-8");
inputData.append(charset.decode(inputBuffer).array()); //解码 改成这样后,再也不抛什么异常了,使用charset.decode()后,连异常都不需要捕获了。 经过测试,CharsetDecoder.decode() 与 Charset.decode() 的性能一样,通过查看API,charset类的所有方法都是线程安全的。

2012-06-10
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: