﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-xiaomage234-文章分类-D-Encoding</title><link>http://www.blogjava.net/xiaomage234/category/1691.html</link><description>行到水穷处,坐看云起时，才发现：其实人生最重要的是找到一些吃的东西；找到一些喝的东西；找到一些可以一起欢笑一起流泪的朋友和一个懂你的人！</description><language>zh-cn</language><lastBuildDate>Fri, 02 Mar 2007 02:38:54 GMT</lastBuildDate><pubDate>Fri, 02 Mar 2007 02:38:54 GMT</pubDate><ttl>60</ttl><item><title>(转)视频聊天原理简介</title><link>http://www.blogjava.net/xiaomage234/articles/6043.html</link><dc:creator>小马歌</dc:creator><author>小马歌</author><pubDate>Mon, 13 Jun 2005 08:04:00 GMT</pubDate><guid>http://www.blogjava.net/xiaomage234/articles/6043.html</guid><wfw:comment>http://www.blogjava.net/xiaomage234/comments/6043.html</wfw:comment><comments>http://www.blogjava.net/xiaomage234/articles/6043.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xiaomage234/comments/commentRss/6043.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xiaomage234/services/trackbacks/6043.html</trackback:ping><description><![CDATA[<P><FONT size=4>视频聊天原理简介,摄像头的原理介绍<BR><BR>伴随着新经济的发展，互联网逐渐成为了世界的主导，在短短数十年的时间里，网络变得越来越完善，越来越可爱，它拉近了人与人之间距离，使我们的地球变成了一个真正的"村落"，让更多的人体会到了"身隔千里远，情系一线间"的快感。 <BR><BR>　　网络的发展也促进了通讯手段的变化，传统的交流方式已经不能满足人们的要求。从E-mai到Internet Phone，网络带来了通讯速度的提升，更降低了通讯成本。而随着宽带网络的普及，人们对网络通讯也有了进一步的要求。宽带网络的发展，改变了传统网络通讯的质量和形式，使交流不再只是局限于普通语言文字，利用视频让天各一方的朋友能够彼此相见。作为实现视频聊天的辅助工具，除了一台配置中等的电脑外，还需要配备一个"眼睛"。通过它你可以看到对方的容颜，也让对方一睹你的风采。 <BR>　　 <BR>　　数码相机可以作为视频聊天的工具，但价格昂贵的它用在视频聊天上却多少有些浪费。相比，摄像头显然更适合于视频聊天使用。不仅画质清晰，捕捉画面速度快，而且价格便宜，售价在三、四百元。另外，由于一般摄像头采用USB接口，还可以集成一些诸如拍照（罗技摄像头）、存储（蓝科火钻"蓝睛灵"）之类的功能，丰富使用空间。 　　 <BR><BR>　　摄像头的原理介绍： <BR><BR>　　现在市场上销售的摄像头都是数字摄像头，它将摄像单元和视频捕捉单元集成在一起，通过微机上的USB接口，可以实现即插即用，非常适合笔记本电脑和品牌机用户。例如一些带有拍摄功能的产品。还有一些有闪盘功能的摄像头产品，在接入电脑后还可以当作32MB的闪盘使用，真正一盘两用。 <BR><IMG src="http://img.zol.com.cn/article/0/752/liSethe8k7tuE.jpg" align=middle border=0>&nbsp;<BR>　　当然，摄像头基本的功能还是视频传输，那么它是依靠增养的原理来实现的呢？所谓视频传输就是将图片一张张传到屏幕，由于传输速度很快，所以可以让大家看到连续动态的画面，就像放电影一样。一般当画面的传输数量达到每秒24帧时，画面就有了连续性。在进行这种图片的传输时，必须将图片进行压缩，一般压缩方式有如H.261、JPEG、MPEG等，否则传输所需的带宽会变得很大。大家用RealPlayer不知是否留意，当播放电影的时候，在播放器的下方会有一个传输速度250kbps、400kbps、1000kbps...画面的质量越高，这个速度也就越大。而摄像头进行视频传输也是这个原理，如果将摄像头的分辨率调到640×480，捕捉到的图片每张大小约为50kb左右，每秒30帧，那么摄像头传输视频所需的速度为50×30/s＝1500kbps＝1.5Mbps。而在实际生活中，人们一般用于网络视频聊天时的分辨率为320×240甚至更低，传输的帧数为每秒24帧。换言之，此时视频传输速率将不到300kbps，人们就可以进行较为流畅的视频传输聊天。如果采用更高的压缩视频方式，如MPEG-1等等，可以将传输速率降低到200kbps不到。这个就是一般视频聊天时，摄像头所需的网络传输速度。 <BR><BR>　　宽带网络： <BR><BR>　　视频压缩上已经可以满足应用的标准，但视频聊天的实现，还需要互联网条件的认可。一般来说，在国内我们可以通过以下几种方式上网： </FONT>
<P>
<TABLE align=center border=0>
<TBODY>
<TR>
<TD><FONT size=4><IMG src="http://it.big5.enorth.com.cn/images/show_images_5/03060610.gif" border=0></FONT></TD></TR></TBODY></TABLE></P><FONT size=4>可以看出，除了56K Modem，ISDN以外，一般的宽带网络都可以满足用户进行视频传输的需求。而根据不同上网方式给用户提供的带宽，还可以自己调节摄像头传输画面的质量，如分辨率、真彩色级别、画面捕捉传输速度等等。比如，当带宽达到2Mbps时，我们就可以采用分辨率为640×480，每秒30帧来进行视频聊天，这时不论是画面的质量还是流畅性都是相当高的，如同两个人面对面交流一样。 　　 <BR><BR>　　现在，摄像头正在向着小型化、功能化的方向发展，越来越多的附加功能出现在摄像头产品中，例如前面提到的可以当作移动存储使用的蓝科火钻"蓝睛灵"，再比如雅美达的网眼显示器、罗技的摄像头数码相机等等。另外，还有一些厂商在摄像头的外型上大做文章，推出了外型设计讨巧的"小丸子"、"高达"造型摄像头，深受儿童、女生的喜爱。这么多特色鲜明的产品助阵，再加上网络的环境的完善，难怪摄像头会这样热卖了。</FONT><img src ="http://www.blogjava.net/xiaomage234/aggbug/6043.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xiaomage234/" target="_blank">小马歌</a> 2005-06-13 16:04 <a href="http://www.blogjava.net/xiaomage234/articles/6043.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转)JAVA里字符编码的探索与理解</title><link>http://www.blogjava.net/xiaomage234/articles/5744.html</link><dc:creator>小马歌</dc:creator><author>小马歌</author><pubDate>Wed, 08 Jun 2005 08:49:00 GMT</pubDate><guid>http://www.blogjava.net/xiaomage234/articles/5744.html</guid><wfw:comment>http://www.blogjava.net/xiaomage234/comments/5744.html</wfw:comment><comments>http://www.blogjava.net/xiaomage234/articles/5744.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xiaomage234/comments/commentRss/5744.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xiaomage234/services/trackbacks/5744.html</trackback:ping><description><![CDATA[<P><FONT size=4>众所周知，JAVA为了国际通用，用的是UNICODE来保存里面的字符。而UNICODE只是一个种字符集，字符的存储和表示要用到一定的字符编码格式，而与UNICODE对应的字符编码格式就是我们常看到的UTF-8,UTF-16等等，而UTF-8是最常用的，所以人们常常把它和UNICODE等同起来（我以前就是这样的），这在某些情况下是没有错的，但这样的理解在JAVA里就会产生一些混淆。我们用下面的程序来演示一下。<BR>定义一个字符串</FONT></P>
<P><FONT size=4>&nbsp;&nbsp;&nbsp;&nbsp; String name = "堂";</FONT></P>
<P><FONT size=4>这个字符串就一个字符，把它取出来</FONT></P>
<P><FONT size=4>&nbsp;&nbsp;&nbsp;&nbsp; char c_name = name.charAt(0);</FONT></P>
<P><FONT size=4>JAVA里的char型是十六位的（两个字节），但是如果是用UTF-8的话可能会不只两位（UTF-8是变长存储的），那看来JAVA本身并不是用UTF-8来保存的，口说无凭，做个实验吧。<BR>&nbsp;&nbsp;&nbsp; 首先看看char里保存的内容</FONT></P>
<P><FONT size=4>int low = (c_name) &amp; 0xff;//取c_name的低位</FONT></P>
<P><FONT size=4>int high = (c_name &gt;&gt; 8) &amp; 0xff;//取c_name的高位</FONT></P>
<P><FONT size=4>System.out.println(Integer.toHexString(high) + " " + Integer.toHexString(low));</FONT></P>
<P><FONT size=4>结果是58 02</FONT></P>
<P><FONT size=4>只有两个字节而已（16位），那么真正的UTF-8编码的内容是什么呢，再看看吧。</FONT></P>
<P><FONT size=4>为了方便，我写了一个辅助方法printbyte，作用是把一个byte数组的每个元素按照十六进制格式打印出来，同样为了方便，我把它作为静态方法。</FONT></P>
<DIV style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #e6e6e6; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid">
<DIV><FONT size=4><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">static</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;printbyte(</SPAN><SPAN style="COLOR: #0000ff">byte</SPAN></FONT><FONT size=4><SPAN style="COLOR: #000000">[]&nbsp;bt)<BR><IMG id=Codehighlighter1_45_275_Open_Image onclick="this.style.display='none'; Codehighlighter1_45_275_Open_Text.style.display='none'; Codehighlighter1_45_275_Closed_Image.style.display='inline'; Codehighlighter1_45_275_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_45_275_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_45_275_Closed_Text.style.display='none'; Codehighlighter1_45_275_Open_Image.style.display='inline'; Codehighlighter1_45_275_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN id=Codehighlighter1_45_275_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN></FONT><SPAN id=Codehighlighter1_45_275_Open_Text><FONT size=4><SPAN style="COLOR: #000000">{<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">for</SPAN><SPAN style="COLOR: #000000">&nbsp;(</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">&nbsp;i&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">;&nbsp;i&nbsp;</SPAN><SPAN style="COLOR: #000000">&lt;</SPAN><SPAN style="COLOR: #000000">&nbsp;bt.length;&nbsp;i</SPAN><SPAN style="COLOR: #000000">++</SPAN></FONT><FONT size=4><SPAN style="COLOR: #000000">)<BR><IMG id=Codehighlighter1_101_219_Open_Image onclick="this.style.display='none'; Codehighlighter1_101_219_Open_Text.style.display='none'; Codehighlighter1_101_219_Closed_Image.style.display='inline'; Codehighlighter1_101_219_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><IMG id=Codehighlighter1_101_219_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_101_219_Closed_Text.style.display='none'; Codehighlighter1_101_219_Open_Image.style.display='inline'; Codehighlighter1_101_219_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN id=Codehighlighter1_101_219_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN></FONT><SPAN id=Codehighlighter1_101_219_Open_Text><FONT size=4><SPAN style="COLOR: #000000">{<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">&nbsp;hex&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;(</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">)bt[i]&nbsp;</SPAN><SPAN style="COLOR: #000000">&amp;</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">0xff</SPAN></FONT><FONT size=4><SPAN style="COLOR: #000000">;<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.</SPAN><SPAN style="COLOR: #0000ff">out</SPAN><SPAN style="COLOR: #000000">.print(Integer.toHexString(hex)&nbsp;</SPAN><SPAN style="COLOR: #000000">+</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">"</SPAN></FONT><SPAN style="COLOR: #000000"><FONT size=4>);<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</FONT></SPAN></SPAN><SPAN style="COLOR: #000000"><BR><FONT size=4><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.</FONT></SPAN><FONT size=4><SPAN style="COLOR: #0000ff">out</SPAN><SPAN style="COLOR: #000000">.println(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;length&nbsp;=&nbsp;</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">+</SPAN></FONT><SPAN style="COLOR: #000000"><FONT size=4>bt.length);<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</FONT></SPAN></SPAN></DIV></DIV>
<P><FONT size=4>byte[] utf_8 = name.getBytes("utf-8");</FONT></P>
<P><FONT size=4>printbyte(utf_8);</FONT></P>
<P><FONT size=4>结果是e5 a0 82&nbsp;&nbsp; length = 3</FONT></P>
<P><FONT size=4>哇，三个字节！看来JAVA内部用的真不是UTF-8，那用的是什么呢？UTF-16？看一下便知。</FONT></P>
<P><FONT size=4>&nbsp;&nbsp;&nbsp;&nbsp; byte[] utf_16 = name.getBytes("utf-16");</FONT></P>
<P><FONT size=4>&nbsp;&nbsp;&nbsp;&nbsp; printbyte(utf_16);</FONT></P>
<P><FONT size=4>结果是fe ff 58 02&nbsp;&nbsp; length = 4，靠，四个字节了。咦？后面的低16位不正是和开始c_name的十六进制表示一样的吗？看来JAVA真正的内部字符编码和UTF-16有或多或少的联系。JAVA内部究竟是用的什么字符编码呢？这个问题我也找了很久，后来在THINK IN JAVA 3rd的12章里看到一个例子出现了UTF-16BE，难道是它？</FONT></P>
<P><FONT size=4>&nbsp;&nbsp;&nbsp;&nbsp; byte[] utf_16be = name.getBytes("utf-16be");</FONT></P>
<P><FONT size=4>&nbsp;&nbsp;&nbsp;&nbsp; printbyte(utf_16be);</FONT></P>
<P><FONT size=4>结果出来了：58 02&nbsp;&nbsp; length = 2</FONT></P>
<P><FONT size=4>哈哈，I got it!不多不少两个字节，内容也一样。果然是它。同时我在里面也看到，UNICODE的编码还有一个LE，这里的BE,LE我想应该是bigendian和littleendian吧。<BR></FONT></P><img src ="http://www.blogjava.net/xiaomage234/aggbug/5744.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xiaomage234/" target="_blank">小马歌</a> 2005-06-08 16:49 <a href="http://www.blogjava.net/xiaomage234/articles/5744.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转)struts的国际化--UTF-8编码解决</title><link>http://www.blogjava.net/xiaomage234/articles/5743.html</link><dc:creator>小马歌</dc:creator><author>小马歌</author><pubDate>Wed, 08 Jun 2005 08:39:00 GMT</pubDate><guid>http://www.blogjava.net/xiaomage234/articles/5743.html</guid><wfw:comment>http://www.blogjava.net/xiaomage234/comments/5743.html</wfw:comment><comments>http://www.blogjava.net/xiaomage234/articles/5743.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/xiaomage234/comments/commentRss/5743.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xiaomage234/services/trackbacks/5743.html</trackback:ping><description><![CDATA[<SPAN class=myp111><FONT id=zoom><FONT size=4>本篇我们来讨论一下struts的国际化编程问题，即所谓的i18n编程问题，这一篇我们讨论其基础部分。与这个问题紧密相关的是在各java论坛中被频繁提及的中文乱码问题，因为，英、美编程人员较少涉及到中文乱码问题，因此，这方面的英文资料也是非常奇缺的，同时也很少找到这方面比较完整的中文资料，本文也尝试对中文乱码问题做一些探讨。要解决上述问题，需要有一定的字符集方面的知识，下面，我们就先介绍字符集的有关情况： <BR><BR><B>一、从ASCII到Unicode（UTF-8）</B> <BR><BR>电子计算机技术是从美国开始发展起来的，因为美国使用的文字为英文，美国规定的计算机信息交换用的字符编码集是人们熟知的扩展ASCII码，它以8bit字节为单位存储，ASCII的0-31及127为控制符，32-126为可见字符，包括所有的英文字母，阿拉伯数字和其他一些常见符号，128-255的ASCII码则没有定义。 <BR><BR>ASCII对英语国家是够用了，但对其他西欧国家却不够用，因此，人们将ASCII扩展到0-255的范围，形成了ISO-8859-1字符集。值得一提的是，因为考虑到程序中处理的信息大多是西文信息，因此有些WEB容器（如：Tomcat4.x）在处理所接收到的request字符串时，如果您没指定request的编码方式则系统就缺省地采用ISO-8859-1，明白这一点对理解后面的问题会有帮助。 <BR><BR>相比西方的拼音文字，东方的文字（如中文）的字符数要大得多，根本不可能在一个字节内将它们表示出来，因此，它们以两个字节为单位存储，以中文国标字符集GB2312为例，它的第一个字节为128-255。系统可以据此判断，若第一个字节大于127，则把与该字节后紧接着的一个字节结合起来共两个字节组成一个中文字符。这种由多个字节存储一个字符的字符集叫多字节字符集（MultiByte Charsets），对应的象ASCII这种用一个字节存储一个字符的字符集叫单字节字符集（SingleByte Charsets）。在GB2312字符集中，ASCII字符仍然用一个字节存储，换句话说该ASCII是该字符集的子集。 <BR><BR>GB2312只包含数千个常用汉字，往往不能满足实际需要，因此，人们对它进行扩展，这就有了我们现在广泛使用的GBK字符集，GBK是现阶段Windows及其他一些中文操作系统的缺省字符集。它包含2万多个字符，除了保持和GB2312兼容外，还包含繁体中文字，日文字符和朝鲜字符。值得注意的是GBK只是一个规范而不是国家标准，新的国家标准是GB18030-2000，它是比GBK包含字符更多的字符集。 <BR><BR>我国的台湾地区使用的文字是繁体字，其字符集是BIG5，而日本采用的字符集则是SJIS。它们的编码方法与GB2312类似，它们的ASCII字符部分是兼容的，但扩展部分的编码则是不兼容的，比如这几种字符集中都有"中文"这两个字符，但他们在各自的字符集中的编码并不相同，这就是用GB2312写成的网页用BIG5浏览时，看到的是乱糟糟的信息的原因。 <BR><BR>可见，在字符集的世界里，呈现给我们的是一个群雄割据的局面，各字符集拥有一块自己的地盘。这给各国和各地区交换信息带来了很大的困难，同时，也给国际化（本地化）编程造成了很大的麻烦。 <BR><BR>常言道："分久必合"，随着国际标准ISO10646定义的通用字符集（Universal Character Set即UCS）的出现，使这种局面发生了彻底的改观。UCS 是所有其他字符集标准的一个超集. 它保证与其他字符集是双向兼容的. 就是说, 如果你将任何文本字符串翻译到 UCS格式, 然后再翻译回原编码, 你不会丢失任何信息。UCS 包含了用于表达所有已知语言的字符。不仅包括拉丁语、希腊语、 斯拉夫语、希伯来语、阿拉伯语、亚美尼亚语和乔治亚语的描述、还包括中文、 日文和韩文这样的象形文字、 以及平假名、片假名、 孟加拉语、 旁遮普语果鲁穆奇字符(Gurmukhi)、 泰米尔语、印.埃纳德语(Kannada)、Malayalam、泰国语、 老挝语、 汉语拼音(Bopomofo)、Hangul、 Devangari、Gujarati、Oriya、Telugu 以及其他数也数不清的语。对于还没有加入的语言， 由于正在研究怎样在计算机中最好地编码它们， 因而最终它们都将被加入。 <BR><BR>ISO 10646 定义了一个 31 位的字符集。 然而， 在这巨大的编码空间中， 迄今为止只分配了前 65534 个码位 (0x0000 到 0xFFFD)。 这个 UCS 的 16位子集称为 基本多语言面 (Basic Multilingual Plane, BMP)。 将被编码在 16 位 BMP 以外的字符都属于非常特殊的字符(比如象形文字)， 且只有专家在历史和科学领域里才会用到它们。 <BR><BR>UCS 不仅给每个字符分配一个代码， 而且赋予了一个正式的名字。 表示一个 UCS 值的十六进制数， 通常在前面加上 "U+", 就象 U+0041 代表字符"拉丁大写字母A"。 UCS 字符 U+0000 到 U+007F 与 US-ASCII(ISO 646) 是一致的， U+0000 到 U+00FF 与 ISO 8859-1(Latin-1) 也是一致的。这里要注意的是它是以16bit为单位存储，即便对字母"A"也是用16bit，这是与前面介绍的所有字符集不同的地方。 <BR><BR>历史上，在国际标准化组织研究ISO10646标准的同时，另一个由多语言软件制造商组成的协会也在从事创立单一字符集的工作，这就是现在人们熟知的Unicode。幸运的是，1991年前后ISO10646和Unicode的参与者都认识到，世界上不需要两个不同的单一字符集。他们合并双方的工作成果，并为创立单一编码表而协同工作。两个项目仍都存在并独立地公布各自的标准，都同意保持ISO10646和Unicode的码表兼容，并紧密地共同调整任何未来的扩展。这与当年在PC机上的操作系统MS-dos与PC-dos的情形有些相象。后面，我们将视ISO10646和Unicode为同一个东西。 <BR><BR>有了Unicode，字符集问题接近了完美的解决，但不要高兴得过早。由于历史的原因：一些操作系统如：Unix、Linux等都是基于ASCII设计的。此外，还有一些数据库管理系统软件如：Oracle等也是围绕ASCII来设计的(从其8i的白皮书上介绍的设置系统字符集和字段的字符集中可以间接地看到这一点)。在这些系统中直接用Unicode会导致严重的问题。用这些编码的字符串会包含一些特殊的字符， 比如 '\0' 或 '/'， 它们在 文件名和其他 C 库函数参数里都有特别的含义。 另外， 大多数使用 ASCII 文件的 UNIX 下的工具， 如果不进行重大修改是无法读取 16 位的字符的。 基于这些原因， 在文件名, 文本文件, 环境变量等地方，直接使用Unicode是不合适的。 <BR><BR>在 ISO 10646-1 Annex R 和 RFC 2279 里定义的 UTF-8 （Unicode Transformation Form 8-bit form）编码没有这些问题。 <BR><BR>UTF-8 有以下一些特性： <BR><BR>UCS 字符 U+0000 到 U+007F (ASCII) 被编码为字节 0x00 到 0x7F (ASCII 兼容)。 这意味着只包含 7 位 ASCII 字符的文件在 ASCII 和 UTF-8 两种编码方式下是一样的。 <BR><BR>所有 &gt;U+007F 的 UCS 字符被编码为一个多个字节的串， 每个字节都有标记位集。 因此，ASCII 字节 (0x00-0x7F) 不可能作为任何其他字符的一部分。 <BR><BR>表示非 ASCII 字符的多字节串的第一个字节总是在 0xC0 到 0xFD 的范围里, 并指出这个字符包含多少个字节。 多字节串的其余字节都在 0x80 到 0xBF 范围里。 这使得重新同步非常容易， 并使编码无国界，且很少受丢失字节的影响。 <BR><BR>UTF-8 编码字符理论上可以最多到 6 个字节长， 然而 16 位 BMP 字符最多只用到 3 字节长。 <BR><BR>字节 0xFE 和 0xFF 在 UTF-8 编码中从未用到。 <BR><BR>通过，UTF-8这种形式，Unicode终于可以广泛的在各种情况下使用了。在讨论struts的国际化编程之前，我们先来看看我们以前在jsp编程中是怎样处理中文问题以及我们经常遇到的：<BR></FONT><SPAN class=myp111><FONT id=zoom><FONT size=4><B>二、中文字符乱码的原因及解决办法</B> <BR><BR>java的内核是Unicode的，也就是说，在程序处理字符时是用Unicode来表示字符的，但是文件和流的保存方式是使用字节流的。在java的基本数据类型中，char是Unicode的，而byte是字节，因此，在不同的环节java要对字节流和char进行转换。这种转换发生时如果字符集的编码选择不当，就会出现乱码问题。 <BR><BR>我们常见的乱码大致有如下几种情形：<BR>1、汉字变成了问号"？"<BR>2、有的汉字显示正确，有的则显示错误<BR>3、显示乱码（有些是汉字但并不是你预期的）<BR>4、读写数据库出现乱码 <BR><BR>下面我们逐一对它们出现的原因做一些解释： <BR><BR>首先，我们讨论汉字变成问号的问题。 <BR><BR>Java中byte与char相互转换的方法在sun.io包中。其中，byte到char的常用转换方法是：<BR>public static ByteToCharConverter getConverter(String encoding); <BR><BR>为了便于大家理解，我们先来做一个小实验：比如，汉字"你"的GBK编码为0xc4e3，其Unicode编码是\u4f60。我们的实验是这样的，先有一个页面比如名为a_gbk.jsp输入汉字"你"，提交给页面b_gbk.jsp。在b_gbk.jsp文件中以某种编码方式得到"你"的字节数组，再将该数组以某种编码方式转换成char，如果得到的char值是0x4f60则转换是正确的。 <BR><BR>a_gbk.jsp的代码如下： <BR><BR><CCID_NOBR></FONT>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE><FONT size=4>&lt;%@ page contentType="text/html; charset=GBK" language="java" import="java.sql.*" errorPage="" %&gt;
&lt;table width="611" border="0" align="center" cellpadding="0" cellspacing="0"&gt;
  &lt;tr&gt;
    &lt;td&gt;&amp;nbsp;&lt;/td&gt;
    &lt;td class="bigword"&gt;&amp;nbsp;&lt;/td&gt;
    &lt;td&gt;&amp;nbsp;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td width="100"&gt;&amp;nbsp;&lt;/td&gt;
    &lt;td class="bigword"&gt;Input&lt;/td&gt;
    &lt;td width="100"&gt;&amp;nbsp;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;&amp;nbsp;&lt;/td&gt;
    &lt;td class="bigword"&gt;&amp;nbsp;&lt;/td&gt;
    &lt;td&gt;&amp;nbsp;&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;
&lt;table width="611" border="0" align="center" cellpadding="0" cellspacing="0"&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;form method="post" action="b_gbk.jsp"&gt;
        &lt;table width="611" border="0" cellpadding="0" cellspacing="0"&gt;
          &lt;tr&gt;
            &lt;td width="100" align="right"&gt;&lt;/td&gt;
            &lt;td&gt;&lt;input name="ClsID" type="text" class="word" id="ClsID" maxlength="2" &gt;
              *&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td width="100" align="right"&gt;&amp;nbsp;&lt;/td&gt;
            &lt;td&gt;&lt;input name="btn" type="submit" value="OK"&gt;
             &lt;/td&gt;
          &lt;/tr&gt;
        &lt;/table&gt;
      &lt;/form&gt;&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;</CCID_CODE></FONT></PRE></TD></TR></TBODY></TABLE></CCID_NOBR><BR><BR><FONT size=4>b_gbk.jsp的代码如下： <BR><BR><CCID_NOBR></FONT>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE><FONT size=4>&lt;%@ page contentType="text/html; charset=GBK" import="sun.io.*,java.util.*" %&gt;
&lt;%
String a=(String)request.getParameter("ClsID");
byte b[]=a.getBytes("ISO8859-1");
for(int j=0;j&lt;b.length;j++){
  out.println(Integer.toHexString(b[j])+"&lt;br&gt;");
}
ByteToCharConverter convertor=ByteToCharConverter.getConverter("GBK");
char[] c=convertor.convertAll(b);
out.println("b length:"+b.length+"&lt;br&gt;");
out.println("c length:"+c.length+"&lt;br&gt;");
for(int i=0;i&lt;c.length;i++){
 	out.println(Integer.toHexString(c[i])+"&lt;br&gt;");
}
String a1=new String(a.getBytes("ISO8859-1"),"GBK");
%&gt;
&lt;%="a是:"+a%&gt;&lt;br&gt;
&lt;%="a1是:"+a1%&gt;</CCID_CODE></FONT></PRE></TD></TR></TBODY></TABLE></CCID_NOBR><BR><BR><FONT size=4>在浏览器中打开a_gbk.jsp并输入一个"你"字，点击OK按钮提交表单，则会出现如图1所示的结果： <BR><BR><IMG src="http://industry.ccidnet.com/pub/attachment/2004/9/340196.jpg"> <BR><BR>图1 <BR><BR>从图1可以看出，在b_gbk.jsp中这样将byte转换为char是正确的，即得到的char是\u4f60。这里要注意的是：byte b[]=a.getBytes("ISO8859-1");中的编码是ISO8859-1，这就是我们前面提到的有些web容器在您没有指定request的字符集时它就采用缺省的ISO8859-1。 <BR><BR>从图1中我们还看到表达式<%="a是:"+a%>中的a并没有正确地显示"你"而是变成"??"这是什么原因呢？这里的a是作为一个String被显示的，我们来看看我们常用的String构造函数： <BR><BR>String(byte[] bytes,String encoding); <BR><BR>在国标平台上，该函数会认为bytes是按GBK编码的，如果后一个参数省略，它也会认为是encoding是GBK。 <BR><BR>对前一个参数就相当于将b_gbk.jsp文件的这句byte b[]=a.getBytes("ISO8859-1");中的ISO8859-1改为GBK，这样显然在GBK字符集中找不到相应的目的编码，它给出的结果是0x3f、0x3f。因此，就会显示为"??"，这也就是造成乱码的第一种现象的原因。我们的例子是演示的从byte到char的转换过程，相反的过程也会造成同样的问题，限于篇幅，就不在此讨论了，大家自己可以做类似的实验来验证。 <BR><BR>解决该问题的方法就是象例子中a1那样，在获取byte数组时，指定编码为ISO8859-1。 <BR><BR>接下来，我们讨论有些汉字能正常显示，有些不能正常显示的问题。 <BR><BR>如果我们将String a1=new String(a.getBytes("ISO8859-1"),"GBK");中的GBK改为GB2312则象朱镕基的"镕"字就不能正常显示，这是因为该字是GBK中的字符而在GB2312中不存在。 <BR><BR>解决上述两种问题的方法就是象a1那样构造String，也就是人们常说的同时也是常用的转码的方法。采用这种方法会在程序中到处出现这种语句，特别是在Struts中，Struts有一个回写表单的功能，在回写时也要做这种转换，这样的语句差不多要多一倍。因此，这是个比较笨拙的方法，有没有简捷一些的方法呢？其实是有的，只要在取得request的字符串前加上request.setCharacterEncoding("GBK");这句，指定request的字符集。则<%="a是:"+a%>中的a就能正常显示，a1反而不能正常显示。此时要将byte b[]=a.getBytes("ISO8859-1");中的ISO8859-1变成GBK，从byte到char的转换才是正确的，这就是此时a能正常显示而a1反而不能正常显示的原因。如果此时要a1正常显示则必须将String a1=new String(a.getBytes("ISO8859-1"),"GBK");中的ISO8859-1改为GBK。 <BR><BR>很显然，使用request.setCharacterEncoding("GBK");只能解决GBK字符问题，要解决i18n问题则要使用UTF-8来取代GBK。我们接着做上述实验，将a_gbk.jsp和b_gbk.jsp分别另存为a.jsp和b.jsp将文件中的GBK改为UTF-8，更改后的代码分别如下： <BR><BR>a.jsp代码： <BR><BR><CCID_NOBR></FONT>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6><PRE><CCID_CODE><FONT size=4>&lt;%@ page contentType="text/html; charset=UTF-8" language="java" import="java.sql.*" errorPage="" %&gt;

&lt;table width="611" border="0" align="center" cellpadding="0" cellspacing="0"&gt;
  &lt;tr&gt;
    &lt;td&gt;&amp;nbsp;&lt;/td&gt;
    &lt;td class="bigword"&gt;&amp;nbsp;&lt;/td&gt;
    &lt;td&gt;&amp;nbsp;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td width="100"&gt;&amp;nbsp;&lt;/td&gt;
    &lt;td class="bigword"&gt;Input&lt;/td&gt;
    &lt;td width="100"&gt;&amp;nbsp;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;&amp;nbsp;&lt;/td&gt;
    &lt;td class="bigword"&gt;&amp;nbsp;&lt;/td&gt;
    &lt;td&gt;&amp;nbsp;&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;
&lt;table width="611" border="0" align="center" cellpadding="0" cellspacing="0"&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;form method="post" action="b.jsp"&gt;
        &lt;table width="611" border="0" cellpadding="0" cellspacing="0"&gt;
          &lt;tr&gt;
            &lt;td width="100" align="right"&gt;&lt;/td&gt;
            &lt;td&gt;&lt;input name="ClsID" type="text" class="word" id="ClsID" maxlength="2" &gt;
              *&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td width="100" align="right"&gt;&amp;nbsp;&lt;/td&gt;
            &lt;td&gt;&lt;input name="btn" type="submit" value="OK"&gt;
             &lt;/td&gt;
          &lt;/tr&gt;
        &lt;/table&gt;
      &lt;/form&gt;&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;
b.jsp代码：
&lt;ccid_nobr&gt;
&lt;table width="400" border="1" cellspacing="0" cellpadding="2" 
 bordercolorlight = "black" bordercolordark = "#FFFFFF" align="center"&gt;
&lt;tr&gt;
    &lt;td bgcolor="e6e6e6" class="code" style="font-size:9pt"&gt;
    &lt;pre&gt;&lt;ccid_code&gt;  &lt;%@ page contentType="text/html; charset=UTF-8" import="sun.io.*,java.util.*" %&gt;

&lt;%
request.setCharacterEncoding("UTF-8");
String a=(String)request.getParameter("ClsID");
byte b[]=a.getBytes("UTF-8");
for(int j=0;j&lt;b.length;j++){
  out.println(Integer.toHexString(b[j])+"&lt;br&gt;");
}
ByteToCharConverter convertor=ByteToCharConverter.getConverter("UTF-8");
char[] c=convertor.convertAll(b);
out.println("b length:"+b.length+"&lt;br&gt;");
out.println("c length:"+c.length+"&lt;br&gt;");
for(int i=0;i&lt;c.length;i++){
  out.println(Integer.toHexString(c[i])+"&lt;br&gt;");
}
String a1=new String(a.getBytes("UTF-8"),"UTF-8");
%&gt;
&lt;%="a是:"+a%&gt;&lt;br&gt;
&lt;%="a1是:"+a1%&gt;</CCID_CODE></FONT></PRE></TD></TR></TBODY></TABLE></CCID_NOBR><BR><BR><FONT size=4>再在a.jsp中输入"你"字，你会发现显示结果中，一个汉字是用三个byte表示的，它们的值分别是0xe4、0xbd、0xa0，也就是说用UTF-8来表示汉字，每个汉字要比GBK多占用一个byte，这也是使用UTF-8要多付出的一点代价吧。 <BR><BR>现在，我们讨论一下第三个问题，即显示乱码，有些莫名其妙的汉字并不是你预期的结果。 <BR><BR>在上例中将String a1=new String(a.getBytes("UTF-8"),"UTF-8");改为String a1=new String(a.getBytes("UTF-8"),"GBK");再输入"你"字，则a1会显示成"浣?"，您只要看一看"浣"的UTF-8码和GBK码就会知道其中的奥秘了。 <BR><BR>下面，我们讨论一下最后一个问题，就是读写数据库时出现乱码。 <BR><BR>现在一些常用的数据库都支持数据库encoding，也就是说在创建数据库时可以指定它自己的字符集设置，数据库数据以指定的编码形式存储。当应用程序访问数据库时，在入口和出口处都会有encoding转换。如果，在应用程序中字符本来已变成了乱码，当然也就无法正确地转换为数据库的字符集了。数据库的encoding可根据需要来设置，比如要支持简、繁体中文、日、韩、英语选GBK，如果还要支持其他语言最好选UTF-8。</FONT></FONT></SPAN></FONT></SPAN><img src ="http://www.blogjava.net/xiaomage234/aggbug/5743.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xiaomage234/" target="_blank">小马歌</a> 2005-06-08 16:39 <a href="http://www.blogjava.net/xiaomage234/articles/5743.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转)深入剖析JSP和Servlet对中文的处理过程 </title><link>http://www.blogjava.net/xiaomage234/articles/5741.html</link><dc:creator>小马歌</dc:creator><author>小马歌</author><pubDate>Wed, 08 Jun 2005 08:33:00 GMT</pubDate><guid>http://www.blogjava.net/xiaomage234/articles/5741.html</guid><wfw:comment>http://www.blogjava.net/xiaomage234/comments/5741.html</wfw:comment><comments>http://www.blogjava.net/xiaomage234/articles/5741.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xiaomage234/comments/commentRss/5741.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xiaomage234/services/trackbacks/5741.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 概述&nbsp;世界上的各地区都有本地的语言。地区差异直接导致了语言环境的差异。在开发一个国际化程序的过程中，处理语言问题就显得很重要了。这是一个世界范围内都存在的问题，所以，Java提供了世界性的解决方法。本文描述的方法是用于处理中文的，但是，推而广之，对于处理世界上其它国家和地区的语言同样适用。汉字是双字节的。所谓双字节是指一个双字要占用两个BYTE的位置（即16位），分别称为...&nbsp;&nbsp;<a href='http://www.blogjava.net/xiaomage234/articles/5741.html'>阅读全文</a><img src ="http://www.blogjava.net/xiaomage234/aggbug/5741.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xiaomage234/" target="_blank">小马歌</a> 2005-06-08 16:33 <a href="http://www.blogjava.net/xiaomage234/articles/5741.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>