- 浏览: 599255 次
- 性别:
- 来自: 上海
-
文章分类
- 全部博客 (154)
- java (31)
- Struts (3)
- Hibernate (8)
- Spring (6)
- JS (14)
- DWR (1)
- Oracle (1)
- SQL Server (0)
- JSF (0)
- JPA (0)
- Grails (3)
- Ajax (1)
- Extjs (0)
- jQuery (4)
- MySQL (2)
- 正则表达式 (2)
- 其他 (6)
- 计算机应用 (7)
- Groovy (8)
- Google (1)
- Web (2)
- MongoDB Java Driver (1)
- mongodb (1)
- Linux (3)
- HTML (1)
- Tomcat (3)
- Eclipse (2)
- JSP (1)
- 缓存 (1)
- 动态 (1)
- 问题与解决 (3)
- HY (1)
- Android (35)
- LBS (1)
最新评论
-
u012136165:
list 方法:纠正:[2,5].add(1,9) ...
Groovy的list和map -
bruce.yuan:
误人子弟的文章。已经看到N个人转了这个帖子,这要贻害多少新人啊 ...
理解并解决GBK转UTF-8奇数中文乱码 -
思念-悲伤:
特意登录上来,感谢下!
理解String的compareTo()方法返回值 -
bo_hai:
总结的好,有效。
理解String的compareTo()方法返回值 -
u012678420:
在onCreate方法中获取某个View的宽度和高度
最近在做一个反馈功能,把数据反馈到对方公司网站,我公司是GBK编码,对方公司是UTF-8编码。因此,我需要将GBK编码数据转换成UTF-8编码数据,这样对方网站才不会乱码。最简单的方法是将HttpClient的ContentCharset设置为utf-8;如果ContentCharset是gbk并且又不想设置为utf-8,那么就需要将数据转换成UTF-8编码再发到对方网站。
问题出现:GBK转UTF-8时,奇数个中文会乱码,偶数个中文不会乱码。
三个中文
public static void encodeError() throws UnsupportedEncodingException { String gbk = "我来了"; String utf8 = new String(gbk.getBytes("UTF-8")); //模拟UTF-8编码的网站显示 System.out.println(new String(utf8.getBytes(),"UTF-8")); } /* 我来?? */
前面三个中文,后面一个中文,都是奇数
public static void encodeError2() throws UnsupportedEncodingException { String gbk = "今年是2011年"; String utf8 = new String(gbk.getBytes("UTF-8")); //模拟UTF-8编码的网站显示 System.out.println(new String(utf8.getBytes(),"UTF-8")); } /* 今年??011?? */
原因:为什么只有奇数个中文才乱码,偶数个却不乱码?下面来分析原因
public static void analyze() throws UnsupportedEncodingException { String gbk = "我来了"; String utf8 = new String(gbk.getBytes("UTF-8")); for (byte b : gbk.getBytes("UTF-8")) { System.out.print(b + " "); } System.out.println(); for (byte b : utf8.getBytes()) { System.out.print(b + " "); } } /* -26 -120 -111 -26 -99 -91 -28 -70 -122 -26 -120 -111 -26 -99 -91 -28 -70 63 */
注意最后一个字节不同,上面一行才是正确的UTF-8编码。那么为什么下面一行最后一个字节是63,而不是-122呢?这就是导致乱码的原因所在。
GBK编码是一个中文2个字节,而UTF-8编码是一个中文3个字节,当我们调用getBytes("UTF-8")方法时,会通过计算来增加字节,使得从GBK的2个字节变成UTF-8对应的3个字节。因此,上例3个中文输出了9个字节。
这里讲一下怎么通过计算增加字节,不深究的读者可以跳过此段。为了醒目,直接用代码讲解
public static void gbk2Utf() throws UnsupportedEncodingException { String gbk = "我来了"; char[] c = gbk.toCharArray(); byte[] fullByte = new byte[3*c.length]; for (int i=0; i<c.length; i++) { String binary = Integer.toBinaryString(c[i]); StringBuffer sb = new StringBuffer(); int len = 16 - binary.length(); //前面补零 for(int j=0; j<len; j++){ sb.append("0"); } sb.append(binary); //增加位,达到到24位3个字节 sb.insert(0, "1110"); sb.insert(8, "10"); sb.insert(16, "10"); fullByte[i*3] = Integer.valueOf(sb.substring(0, 8), 2).byteValue();//二进制字符串创建整型 fullByte[i*3+1] = Integer.valueOf(sb.substring(8, 16), 2).byteValue(); fullByte[i*3+2] = Integer.valueOf(sb.substring(16, 24), 2).byteValue(); } //模拟UTF-8编码的网站显示 System.out.println(new String(fullByte,"UTF-8")); }
现在我们来找出最后一个字节是63,而不是-122的原因。
public static void analyze2() throws UnsupportedEncodingException { String gbk = "我来了"; byte[] utfBytes = gbk.getBytes("UTF-8");//得到9个字节 String utf8 = new String(utfBytes);//问题就出在这 System.out.print(utf8); } /* 鎴戞潵浜? */
因为文件是GBK编码,new String(utfBytes)默认就是new String(utfBytes,"GBK")。它会2个字节2个字节地转换成字符,当字节是奇数时最后1个字节转字符就会计算错误,然后直接赋予最后这个字符为?,对应ASCII代码就是63。
解决问题
保证字节正确才是硬道理。当调用getBytes("UTF-8")转换成字节数组后,创建ISO-8859-1编码的字符串,ISO-8859-1编码是一个字节对应一个字符,因此不会使最后一个字节错误。
public static void correctEncode() throws UnsupportedEncodingException { String gbk = "我来了"; String iso = new String(gbk.getBytes("UTF-8"),"ISO-8859-1"); for (byte b : iso.getBytes("ISO-8859-1")) { System.out.print(b + " "); } System.out.println(); //模拟UTF-8编码的网站显示 System.out.println(new String(iso.getBytes("ISO-8859-1"),"UTF-8")); } /* -26 -120 -111 -26 -99 -91 -28 -70 -122 我来了 */
评论
lz先搞清楚各种编码的码表再说。解码编码说到底就是一个可逆的操作,如同序列化一样。不可逆了就会出现乱码,你要想准确解码你只要搞清楚它是哪种编码方式编码的就行了。
是1个到6个
到底几个,到底几个,到底几个????
http://www.ietf.org/rfc/rfc3629.txt
是1个到6个
到底几个,到底几个,到底几个????
是1个到6个
String str = new String("我来了".getBytes("GBK")); byte[] bt = str.getBytes("UTF-8"); System.out.println(bt.length); for(int i=0;i<bt.length;i++){ System.out.print(bt[i]+" "); } String str1 = new String(bt,"UTF-8"); System.out.println(new String(str1.getBytes(),"GBK"));
<div class="quote_div">..........
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span>字符串编码迷思:</span></p>
<table class="MsoNormalTable" style="width: 100.0%; border-collapse: collapse;" border="0" cellspacing="0" cellpadding="0" width="100%"><tbody><tr>
<td style="width: 100.0%; background: silver; padding: 0cm 5.4pt 0cm 5.4pt;" width="100%" valign="top">
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span lang="EN-US">new String(input.getBytes("ISO-8859-1"), "GB18030")</span></p>
</td>
</tr></tbody></table>
<p class="MsoNormal" style="text-align: left; text-indent: 21.0pt; line-height: 16.5pt;" align="left"><span>上面这段代码代表什么?有人会说:</span><span lang="EN-US"> </span><span>“把</span><span lang="EN-US">input</span><span>字符串从</span><span lang="EN-US">ISO-8859-1</span><span>编码方式转换成</span><span lang="EN-US">GB18030</span><span>编码方式”。如果这种说法正确,那么又如何解释我们刚提到的</span><span lang="EN-US">java</span><span>字符串都采用</span><span lang="EN-US">unicode</span><span>编码呢?</span></p>
<p class="MsoNormal" style="text-align: left; text-indent: 21.0pt; line-height: 16.5pt;" align="left"><span>这种说法不仅是欠妥的,而且是大错特错的,让我们一一来分析,其实事实是这样的:我们本应该用</span><span lang="EN-US">GB18030</span><span>的编码来读取数据并解码成字符串,但结果却采用了</span><span lang="EN-US">ISO-8859-1</span><span>的编码,导致生成一个错误的字符串。要恢复,就要先把字符串恢复成原始字节数组,然后通过正确的编码</span><span lang="EN-US">GB18030</span><span>再次解码成字符串(即把以</span><span lang="EN-US">GB18030</span><span>编码的数据转成</span><span lang="EN-US">unicode</span><span>的字符串)。注意,字符串永远都是</span><span lang="EN-US">unicode</span><span>编码的。</span></p>
<p class="MsoNormal" style="text-align: left; text-indent: 21.0pt; line-height: 16.5pt;" align="left"><span>但编码转换并不是负负得正那么简单,这里我们之所以可以正确地转换回来,是因为</span><span lang="EN-US"> </span><span lang="EN-US">ISO8859-1</span><span lang="EN-US"> </span><span>是单字节编码,所以每个字节被按照原样</span><span lang="EN-US"> </span><span>转换为</span><span lang="EN-US"> </span><span lang="EN-US">String</span><span lang="EN-US"> </span><span>,也就是说,虽然这是一个错误的转换,但编码没有改变,所以我们仍然有机会把编码转换回来!</span><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span>总结:</span></p>
<p class="MsoNormal" style="text-align: left; text-indent: 21.0pt; line-height: 16.5pt;" align="left"><span>所以,我们在处理</span><span lang="EN-US">java</span><span>的编码问题时,要分清楚三个概念:</span><span lang="EN-US">Java</span><span>采用的编码:</span><span lang="EN-US">unicode</span><span>,</span><span lang="EN-US">JVM</span><span>平台默认字符集和外部资源的编码。</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
</div>
<p>这个地方是亮点</p>
是的,ISO-8859-1是一个字节表示一个字符,UTF-8是三个字节表示一个字符。
准确的说UTF-8表示中文时一般用3个字节
是的,ISO-8859-1是一个字节表示一个字符,UTF-8是三个字节表示一个字符。
这种说法不对,UTF-8有一个字节的字符也有2个字节的字符也有3个字节的字符
准确说是3个字节表示一个中文字符,英文字符或数字可以是1个字节,也可以是3个字节
String iso = new String(gbk.getBytes("UTF-8"),"UTF-8");
System.out.println(iso);
直接这样不行吗?
+1
String gbk = "我来了";
String iso = new String(gbk.getBytes("UTF-8"),"UTF-8");
for (byte b : gbk.getBytes("UTF-8")) {
System.out.print(b + " ");
}
System.out.println();
for (byte b : iso.getBytes()) {
System.out.print(b + " ");
}
System.out.println();
for (byte b : gbk.getBytes()) {
System.out.print(b + " ");
}
/*
-26 -120 -111 -26 -99 -91 -28 -70 -122
-50 -46 -64 -76 -63 -53
-50 -46 -64 -76 -63 -53
*/
兄弟,自己体会
System.out.print(b + " ");
}
String iso = new String(gbk.getBytes("UTF-8"),"UTF-8");
System.out.println(iso);
直接这样不行吗?
lz那样转换纯粹是脱了裤子放屁,直接new String(s.getBytes("UTF-8"), "UTF-8")就搞定了非要中间加一层iso-8859-1的转换。
先utf8“编码”成byte数组,然后再utf8“解码”成字符串就可以了。
的确lz没有说到点子上,远程通信最终都要转成字节流的,关键是你传给outputstream的时候把String转成什么编码的字节数组,前面任你怎么转都是没有意义的
+1 这个是对的
确实这是对的,已测试

String gbk = "我来了";
String iso = new String(gbk.getBytes("UTF-8"),"UTF-8");
for (byte b : gbk.getBytes("UTF-8")) {
System.out.print(b + " ");
}
System.out.println();
for (byte b : iso.getBytes()) {
System.out.print(b + " ");
}
/*
-26 -120 -111 -26 -99 -91 -28 -70 -122
-50 -46 -64 -76 -63 -53
*/
楼主提出的解决方案中有这样一句话:
“int len = 16 - binary.length();”
为啥用16作为减数呢
如果binary.length()是15,就在前面加个0,达到16位二进制
是的,ISO-8859-1是一个字节表示一个字符,UTF-8是三个字节表示一个字符。
这种说法不对,UTF-8有一个字节的字符也有2个字节的字符也有3个字节的字符
准确说是3个字节表示一个中文字符
楼主提出的解决方案中有这样一句话:
“int len = 16 - binary.length();”
为啥用16作为减数呢
String iso = new String(gbk.getBytes("UTF-8"),"UTF-8");
System.out.println(iso);
直接这样不行吗?
lz那样转换纯粹是脱了裤子放屁,直接new String(s.getBytes("UTF-8"), "UTF-8")就搞定了非要中间加一层iso-8859-1的转换。
先utf8“编码”成byte数组,然后再utf8“解码”成字符串就可以了。
的确lz没有说到点子上,远程通信最终都要转成字节流的,关键是你传给outputstream的时候把String转成什么编码的字节数组,前面任你怎么转都是没有意义的
+1 这个是对的
确实这是对的,已测试

String iso = new String(gbk.getBytes("UTF-8"),"UTF-8");
System.out.println(iso);
直接这样不行吗?
+1
</p>
<p class="MsoNormal" style="margin-top: 22.5pt; margin-right: 0cm; margin-bottom: 15.0pt; margin-left: 0cm; text-align: left; line-height: 18.0pt;" align="left">下面这篇文章应该能够说到要点上。</p>
<p class="MsoNormal" style="margin-top: 22.5pt; margin-right: 0cm; margin-bottom: 15.0pt; margin-left: 0cm; text-align: left; line-height: 18.0pt;" align="left"><strong><span style="" lang="EN-US">Java</span></strong><strong><span style="">与<span lang="EN-US">Unicode</span></span></strong><strong><span style="" lang="EN-US"></span></strong></p>
<p class="MsoNormal" style="text-align: left; text-indent: 21.0pt; line-height: 16.5pt;" align="left"><span style="" lang="EN-US">Java</span><span style="">的</span><span style="" lang="EN-US">class</span><span style="">文件采用</span><span style="" lang="EN-US">utf8</span><span style="">的编码方式,</span><span style="" lang="EN-US">JVM</span><span style="">运行时采用</span><span style="" lang="EN-US">utf16</span><span style="">。</span><span style="" lang="EN-US">Java</span><span style="">的字符串是</span><span style="" lang="EN-US">unicode</span><span style="">编码的。总之,</span><span style="" lang="EN-US">Java</span><span style="">采用了</span><span style="" lang="EN-US">unicode</span><span style="">字符集,使之易于国际化。</span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US"> </span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US">Java</span><span style="">支持哪些字符集:</span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; text-indent: 21.0pt; line-height: 16.5pt;" align="left"><span style="">即</span><span style="" lang="EN-US">Java</span><span style="">能识别哪些字符集并对它进行正确地处理?查看</span><span style="" lang="EN-US">Charset</span><span style="" lang="EN-US"> </span><span style="">类,最新的</span><span style="" lang="EN-US">JDK</span><span style="">支持</span><span style="" lang="EN-US">160</span><span style="">种字符集。可以通过</span><span style="" lang="EN-US">static</span><span style="">方法</span><span style="" lang="EN-US">availableCharsets</span><span style="">拿到所有</span><span style="" lang="EN-US">Java</span><span style="">支持的字符集。</span><span style="" lang="EN-US"></span></p>
<table class="MsoNormalTable" style="width: 100.0%; border-collapse: collapse;" border="0" cellspacing="0" cellpadding="0" width="100%"><tbody><tr style="">
<td style="width: 100.0%; background: silver; padding: 0cm 5.4pt 0cm 5.4pt;" width="100%" valign="top">
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US">assertEquals(160, Charset.availableCharsets().size()); </span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US"> </span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US">Set<String> charsetNames =
Charset.availableCharsets().keySet(); </span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US"> </span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US">assertTrue(charsetNames.contains("utf-8")); </span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US">assertTrue(charsetNames.contains("utf-16")); </span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US">assertTrue(charsetNames.contains("gb2312")); </span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US"> </span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US">assertTrue(Charset.isSupported("utf-8"));</span><span style="" lang="EN-US"></span></p>
</td>
</tr></tbody></table>
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US"> </span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="">需要在哪些时候注意编码问题?</span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="" align="left"><span style="" lang="EN-US">1.</span><span style="" lang="EN-US"> </span><span style="" lang="EN-US"> </span><span style="">从外部资源读取数据:</span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; text-indent: 21.0pt; line-height: 16.5pt;" align="left"><span style="">这跟外部资源采取的编码方式有关,我们需要使用外部资源采用的字符集来读取外部数据:</span><span style="" lang="EN-US"></span></p>
<table class="MsoNormalTable" style="width: 100.0%; border-collapse: collapse;" border="0" cellspacing="0" cellpadding="0" width="100%"><tbody><tr style="">
<td style="width: 100.0%; background: silver; padding: 0cm 5.4pt 0cm 5.4pt;" width="100%" valign="top">
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US">InputStream is = new
FileInputStream("res/input2.data"); </span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US">InputStreamReader streamReader = new InputStreamReader(is,
"GB18030");</span><span style="" lang="EN-US"></span></p>
</td>
</tr></tbody></table>
<p class="MsoNormal" style="text-align: left; text-indent: 21.0pt; line-height: 16.5pt;" align="left"><span style="">这里可以看到,我们采用了</span><span style="" lang="EN-US">GB18030</span><span style="">编码读取外部数据,通过查看</span><span style="" lang="EN-US">streamReader</span><span style="">的</span><span style="" lang="EN-US">encoding</span><span style="">可以印证:</span><span style="" lang="EN-US"></span></p>
<table class="MsoNormalTable" style="width: 100.0%; border-collapse: collapse;" border="0" cellspacing="0" cellpadding="0" width="100%"><tbody><tr style="">
<td style="width: 100.0%; background: silver; padding: 0cm 5.4pt 0cm 5.4pt;" width="100%" valign="top">
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US">assertEquals("GB18030", streamReader.getEncoding());</span><span style="" lang="EN-US"></span></p>
</td>
</tr></tbody></table>
<p class="MsoNormal" style="text-align: left; text-indent: 21.0pt; line-height: 16.5pt;" align="left"><span style="">正是由于上面我们为外部资源指定了正确的编码,当它转成</span><span style="" lang="EN-US">char</span><span style="">数组时才能正确地进行解码(</span><span style="" lang="EN-US">GB18030 -> unicode</span><span style="">):</span><span style="" lang="EN-US"></span></p>
<table class="MsoNormalTable" style="width: 100.0%; border-collapse: collapse;" border="0" cellspacing="0" cellpadding="0" width="100%"><tbody><tr style="">
<td style="width: 100.0%; background: silver; padding: 0cm 5.4pt 0cm 5.4pt;" width="100%" valign="top">
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US">char[] chars = new char[is.available()]; </span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US">streamReader.read(chars, 0, is.available());</span><span style="" lang="EN-US"></span></p>
</td>
</tr></tbody></table>
<p class="MsoNormal" style="text-align: left; text-indent: 21.0pt; line-height: 16.5pt;" align="left"><span style="">但我们经常写的代码就像下面这样:</span><span style="" lang="EN-US"></span></p>
<table class="MsoNormalTable" style="width: 100.0%; border-collapse: collapse;" border="0" cellspacing="0" cellpadding="0" width="100%"><tbody><tr style="">
<td style="width: 100.0%; background: silver; padding: 0cm 5.4pt 0cm 5.4pt;" width="100%" valign="top">
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US">InputStream is = new
FileInputStream("res/input2.data"); </span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US">InputStreamReader streamReader = new InputStreamReader(is);</span><span style="" lang="EN-US"></span></p>
</td>
</tr></tbody></table>
<p class="MsoNormal" style="text-align: left; text-indent: 21.0pt; line-height: 16.5pt;" align="left"><span style="">这时候</span><span style="" lang="EN-US">InputStreamReader</span><span style="">采用什么编码方式读取外部资源呢?</span><span style="" lang="EN-US">Unicode</span><span style="">?不是,这时候采用的编码方式是</span><span style="" lang="EN-US">JVM</span><span style="">的默认字符集,这个默认字符集在虚拟机启动时决定,通常根据语言环境和底层操作系统的</span><span style="" lang="EN-US"> </span><span style="" lang="EN-US">charset</span><span style="">来确定。可以通过以下方式得到</span><span style="" lang="EN-US">JVM</span><span style="">的默认字符集:</span><span style="" lang="EN-US"></span></p>
<table class="MsoNormalTable" style="width: 100.0%; border-collapse: collapse;" border="0" cellspacing="0" cellpadding="0" width="100%"><tbody><tr style="">
<td style="width: 100.0%; background: silver; padding: 0cm 5.4pt 0cm 5.4pt;" width="100%" valign="top">
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US">Charset.defaultCharset(); </span><span style="" lang="EN-US"></span></p>
</td>
</tr></tbody></table>
<p class="MsoNormal" style="text-align: left; text-indent: 21.0pt; line-height: 16.5pt;" align="left"><span style="">为什么要这样?因为我们从外部资源读取数据,而外部资源的编码方式通常跟操作系统所使用的字符集一样,所以采用这种默认方式是可以理解的。</span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; text-indent: 21.0pt; line-height: 16.5pt;" align="left"><span style="">好吧,那么我通过我的</span><span style="" lang="EN-US">IDE Ideas</span><span style="">创建了一个文件,并以</span><span style="" lang="EN-US">JVM</span><span style="">默认的编码方式从这个文件读取数据,但读出来的数据竟然是乱码。为何?呵呵,其实是因为通过</span><span style="" lang="EN-US">Ideas</span><span style="">创建的文件是以</span><span style="" lang="EN-US">utf-8</span><span style="">编码的。要得到一个</span><span style="" lang="EN-US">JVM</span><span style="">默认编码的文件,通过手工创建一个</span><span style="" lang="EN-US">txt</span><span style="">文件试试吧。</span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="" align="left"><span style="" lang="EN-US">2.</span><span style="" lang="EN-US"> </span><span style="" lang="EN-US"> </span><span style="">字符串和字节数组的相互转换</span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; text-indent: 21.0pt; line-height: 16.5pt;" align="left"><span style="">我们通常通过以下代码把字符串转换成字节数组:</span><span style="" lang="EN-US"></span></p>
<table class="MsoNormalTable" style="width: 100.0%; border-collapse: collapse;" border="0" cellspacing="0" cellpadding="0" width="100%"><tbody><tr style="">
<td style="width: 100.0%; background: silver; padding: 0cm 5.4pt 0cm 5.4pt;" width="100%" valign="top">
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US">"string".getBytes();</span><span style="" lang="EN-US"></span></p>
</td>
</tr></tbody></table>
<p class="MsoNormal" style="text-align: left; text-indent: 21.0pt; line-height: 16.5pt;" align="left"><span style="">但你是否注意过这个转换采用的编码呢?其实上面这句代码跟下面这句是等价的:</span><span style="" lang="EN-US"></span></p>
<table class="MsoNormalTable" style="width: 100.0%; border-collapse: collapse;" border="0" cellspacing="0" cellpadding="0" width="100%"><tbody><tr style="">
<td style="width: 100.0%; background: silver; padding: 0cm 5.4pt 0cm 5.4pt;" width="100%" valign="top">
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US">"string".getBytes(Charset.defaultCharset());</span><span style="" lang="EN-US"></span></p>
</td>
</tr></tbody></table>
<p class="MsoNormal" style="text-align: left; text-indent: 21.0pt; line-height: 16.5pt;" align="left"><span style="">也就是说它根据</span><span style="" lang="EN-US">JVM</span><span style="">的默认编码(而不是你可能以为的</span><span style="" lang="EN-US">unicode</span><span style="">)把字符串转换成一个字节数组。</span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; text-indent: 21.0pt; line-height: 16.5pt;" align="left"><span style="">反之,如何从字节数组创建一个字符串呢?</span><span style="" lang="EN-US"></span></p>
<table class="MsoNormalTable" style="width: 100.0%; border-collapse: collapse;" border="0" cellspacing="0" cellpadding="0" width="100%"><tbody><tr style="">
<td style="width: 100.0%; background: silver; padding: 0cm 5.4pt 0cm 5.4pt;" width="100%" valign="top">
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US">new String("string".getBytes());</span><span style="" lang="EN-US"></span></p>
</td>
</tr></tbody></table>
<p class="MsoNormal" style="text-align: left; text-indent: 21.0pt; line-height: 16.5pt;" align="left"><span style="">同样,这个方法使用平台的默认字符集解码字节的指定数组(这里的解码指从一种字符集到</span><span style="" lang="EN-US">unicode</span><span style="">)。</span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US"> </span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="">字符串编码迷思:</span><span style="" lang="EN-US"></span></p>
<table class="MsoNormalTable" style="width: 100.0%; border-collapse: collapse;" border="0" cellspacing="0" cellpadding="0" width="100%"><tbody><tr style="">
<td style="width: 100.0%; background: silver; padding: 0cm 5.4pt 0cm 5.4pt;" width="100%" valign="top">
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US">new String(input.getBytes("ISO-8859-1"), "GB18030")</span><span style="" lang="EN-US"></span></p>
</td>
</tr></tbody></table>
<p class="MsoNormal" style="text-align: left; text-indent: 21.0pt; line-height: 16.5pt;" align="left"><span style="">上面这段代码代表什么?有人会说:</span><span style="" lang="EN-US"> </span><span style="">“把</span><span style="" lang="EN-US">input</span><span style="">字符串从</span><span style="" lang="EN-US">ISO-8859-1</span><span style="">编码方式转换成</span><span style="" lang="EN-US">GB18030</span><span style="">编码方式”。如果这种说法正确,那么又如何解释我们刚提到的</span><span style="" lang="EN-US">java</span><span style="">字符串都采用</span><span style="" lang="EN-US">unicode</span><span style="">编码呢?</span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; text-indent: 21.0pt; line-height: 16.5pt;" align="left"><span style="">这种说法不仅是欠妥的,而且是大错特错的,让我们一一来分析,其实事实是这样的:我们本应该用</span><span style="" lang="EN-US">GB18030</span><span style="">的编码来读取数据并解码成字符串,但结果却采用了</span><span style="" lang="EN-US">ISO-8859-1</span><span style="">的编码,导致生成一个错误的字符串。要恢复,就要先把字符串恢复成原始字节数组,然后通过正确的编码</span><span style="" lang="EN-US">GB18030</span><span style="">再次解码成字符串(即把以</span><span style="" lang="EN-US">GB18030</span><span style="">编码的数据转成</span><span style="" lang="EN-US">unicode</span><span style="">的字符串)。注意,字符串永远都是</span><span style="" lang="EN-US">unicode</span><span style="">编码的。</span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; text-indent: 21.0pt; line-height: 16.5pt;" align="left"><span style="">但编码转换并不是负负得正那么简单,这里我们之所以可以正确地转换回来,是因为</span><span style="" lang="EN-US"> </span><span style="" lang="EN-US">ISO8859-1</span><span style="" lang="EN-US"> </span><span style="">是单字节编码,所以每个字节被按照原样</span><span style="" lang="EN-US"> </span><span style="">转换为</span><span style="" lang="EN-US"> </span><span style="" lang="EN-US">String</span><span style="" lang="EN-US"> </span><span style="">,也就是说,虽然这是一个错误的转换,但编码没有改变,所以我们仍然有机会把编码转换回来!</span><span style="" lang="EN-US"> </span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="" lang="EN-US"> </span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; line-height: 16.5pt;" align="left"><span style="">总结:</span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal" style="text-align: left; text-indent: 21.0pt; line-height: 16.5pt;" align="left"><span style="">所以,我们在处理</span><span style="" lang="EN-US">java</span><span style="">的编码问题时,要分清楚三个概念:</span><span style="" lang="EN-US">Java</span><span style="">采用的编码:</span><span style="" lang="EN-US">unicode</span><span style="">,</span><span style="" lang="EN-US">JVM</span><span style="">平台默认字符集和外部资源的编码。</span><span style="" lang="EN-US"></span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
发表评论
-
Java创建对象的四种方法
2010-12-24 15:10 1274package test; import java ... -
文件上传
2010-12-16 09:42 1101我用Excel数据导入来说明文件上传问题 <form ... -
GBK编码转成UTF-8编码
2010-12-03 15:49 1528从GBK编码转成UTF-8编码 private String ... -
HttpClient请求
2010-11-24 18:22 1634一个apache的httpclient简单范本,常用在WebS ... -
接收任意个字符串的方法
2010-11-10 11:32 1153public class MutilStringParamsD ... -
有状态会话Bean(SLSB)和无状态会话Bean(SFSB)的区别(转)
2010-09-26 10:01 1926Session Bean:分有状态 ... -
ThreadLocal解决线程安全问题
2010-09-25 16:55 3318//以下代码存在问题 pub ... -
AOP之Hello World
2010-09-14 23:41 1151目标 package com.aop.joinpoint; ... -
理解Socket
2010-09-03 00:31 1315服务器端代码: import java.io.Buffered ... -
理解TreeSet.add()方法
2010-08-31 17:35 3316Set存放不同元素,TreeSet存放不同元素,并且对元素进行 ... -
一道Java面试题
2010-08-25 15:40 1340有两组字符串,A组["A","B ... -
理解+=操作符
2010-08-23 14:52 998今天看到一篇文章(下面给出原文链接),对作者的错误理解予以纠正 ... -
更深入地理解自增自减运算符
2010-08-20 17:27 1198public class DeepTest { public ... -
理解重载与重写
2010-08-20 15:51 1126今天有个朋友问我重载与覆盖的区别,所以我就写好了发给他。在这贴 ... -
暴露属性不安全?
2010-08-17 20:19 1260我们在看书的时候常常看到书上说暴露属性不安全,那么请问下哪里不 ... -
理解继承
2010-08-10 11:52 999这个例子涉及到继承与 ... -
获取properties配置文件信息
2010-08-10 11:32 1734import java.io.IOException; imp ... -
中文字符按拼音排序
2010-06-01 13:12 1653java.util.Comparator cmp = java ... -
线程并发
2010-05-25 21:01 1225进程:表示一个任务。 线程:一种比进程更小的执行单位,依附在进 ... -
了解枚举
2010-05-23 19:05 1554为了了解枚举,先利用反射分析一下它 import java.l ...
相关推荐
idea、Eclipse等项目导入.java文件中文乱码完美解决方案:文件夹下所有GBK编码的.java一键转为utf-8,操作方式:将GBK2UTF8.jar文件考到需要转码项目目录,在当前位置运行控制台,输入命令java -jar GBK2UTF8.jar,...
GBK是中国的国家标准,尽管它的通用性不如UTF-8广泛,但它能够涵盖几乎所有的中文字符,适用于主要面向中文用户的网站。 UTF-8,全称为Unicode Transformation Format - 8 bit,是一种基于Unicode字符集的编码方式...
GBK、UTF-8和ISO-8859-1之间的转换需要注意,偶数个汉字可以在GBK和UTF-8之间互换,而奇数个汉字可能在转换过程中丢失,导致乱码。 总的来说,将Tomcat的`URIEncoding`设置为`UTF-8`是解决大多数中文乱码问题的有效...
常见的中文字符编码方式有UTF-8、GBK等。不同的编码方式会导致不同的结果,因此在处理中文URL时必须明确使用的编码方式。 ### 二、问题分析 #### 2.1 奇数个中文字符乱码原因 中文字符通常由多个字节组成(例如UTF...
4. **地址栏输入中文参数**:这是个特殊问题,因为IE6有一个“以UTF-8发送URL”的选项,如果关闭此选项,IE6将以系统默认编码(可能是GBK或其他编码)发送URL,导致服务器端接收乱码。 解决这类问题的一个关键是...
当UTF-8编码的页面在IE7中解析时,如果`<title>`标签内部存在奇数个全角字符(每个全角字符在UTF-8中占3个字节),IE7可能会将其错误地解析为两个字节,导致半个汉字与`</title>`的开始标签"结合,形成乱码,从而...
//我将文件名getBytes()下,将GBK改成UTF-8。测试了下,貌似没问题, //突然有一次上传一文件时,发现最后几个字乱码,一直是??。在拿些文件测试, // 后来知道了是当文件名为中文奇数时,会乱码,而且还上传不了。...