backup2007

导航

<2024年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

统计

公告

@import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);


常用链接

留言簿(1)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜

2008年1月17日 #

编码问题3转

世界上的各地区都有本地的语言。地区差异直接导致了语言环境的差异。在开发一个国际化程序的过程中,处理语言问题就显得很重要了。

  这是一个世界范围内都存在的问题,所以,Java提供了世界性的解决方法。本文描述的方法是用于处理中文的,但是,推而广之,对于处理世界上其它国家和地区的语言同样适用。

  汉字是双字节的。所谓双字节是指一个双字要占用两个BYTE的位置(即16位),分别称为高位和低位。中国规定的汉字编码为GB2312,这是 强制性的,目前几乎所有的能处理中文的应用程序都支持GB2312。GB2312包括了一二级汉字和9区符号,高位从0xa1到0xfe,低位也是从 0xa1到0xfe,其中,汉字的编码范围为0xb0a1到0xf7fe。

  另外有一种编码,叫做GBK,但这是一份规范,不是强制的。GBK提供了20902个汉字,它兼容GB2312,编码范围为0x8140到0xfefe。GBK中的所有字符都可以一一映射到Unicode 2.0。

  在不久的将来,中国会颁布另一种标准:GB18030-2000(GBK2K)。它收录了藏、蒙等少数民族的字型,从根本上解决了字位不足的问 题。注意:它不再是定长的。其二字节部份与GBK兼容,四字节部分是扩充的字符、字形。它的首字节和第三字节从0x81到0xfe,二字节和第四字节从 0x30到0x39。

  本文不打算介绍Unicode,有兴趣的可以浏览“http://www.unicode.org/”查看更多的信息。Unicode有一个特 性:它包括了世界上所有的字符字形。所以,各个地区的语言都可以建立与Unicode的映射关系,而Java正是利用了这一点以达到异种语言之间的转换。

  在JDK中,与中文相关的编码有:

  表1 JDK中与中文相关的编码列表
编码名称 说明
ASCII 7位,与ascii7相同
ISO8859-1 8-位,与 8859_1,ISO-8859-1,ISO_8859-1,latin1...等相同
GB2312-80 16位,与gb2312,gb2312-1980,EUC_CN,euccn,1381,Cp1381, 1383, Cp1383, ISO2022CN,ISO2022CN_GB...等相同
GBK 与MS936相同,注意:区分大小写
UTF8 与UTF-8相同
GB18030 与cp1392、1392相同,目前支持的JDK很少

  在实际编程时,接触得比较多的是GB2312(GBK)和ISO8859-1。

  为什么会有“?”号

  上文说过,异种语言之间的转换是通过Unicode来完成的。假设有两种不同的语言A和B,转换的步骤为:先把A转化为Unicode,再把Unicode转化为B。

  举例说明。有GB2312中有一个汉字“李”,其编码为“C0EE”,欲转化为ISO8859-1编码。步骤为:先把“李”字转化为 Unicode,得到“674E”,再把“674E”转化为ISO8859-1字符。当然,这个映射不会成功,因为ISO8859-1中根本就没有与 “674E”对应的字符。

  当映射不成功时,问题就发生了!当从某语言向Unicode转化时,如果在某语言中没有该字符,得到的将是Unicode的代码“" uffffd”(“"u”表示是Unicode编码,)。而从Unicode向某语言转化时,如果某语言没有对应的字符,则得到的是“0x3f” (“?”)。这就是“?”的由来。

  例如:把字符流buf =“0x80 0x40 0xb0 0xa1”进行new String(buf, "gb2312")操作,得到的结果是“"ufffd"u554a”,再println出来,得到的结果将是“?啊”,因为“0x80 0x40”是GBK中的字符,在GB2312中没有。

  再如,把字符串String=""u00d6"u00ec"u00e9"u0046"u00bb"u00f9"进行new String (buf.getBytes("GBK"))操作,得到的结果是“3fa8aca8a6463fa8b4”,其中,“"u00d6”在“GBK”中没有对 应的字符,得到“3f”,“"u00ec”对应着“a8ac”,“"u00e9”对应着“a8a6”,“0046”对应着“46”(因为这是ASCII字 符),“"u00bb”没找到,得到“3f”,最后,“"u00f9”对应着“a8b4”。把这个字符串println一下,得到的结果是“?ìéF? ù”。看到没?这里并不全是问号,因为GBK与Unicode映射的内容中除了汉字外还有字符,本例就是最好的明证。

  所以,在汉字转码时,如果发生错乱,得到的不一定都是问号噢!不过,错了终究是错了,50步和100步并没有质的差别。

  或者会问:如果源字符集中有,而Unicode中没有,结果会如何?回答是不知道。因为我手头没有能做这个测试的源字符集。但有一点是肯定的,那就是源字符集不够规范。在Java中,如果发生这种情况,是会抛出异常的。

什么是UTF

  UTF,是Unicode Text Format的缩写,意为Unicode文本格式。对于UTF,是这样定义的:

  (1)如果Unicode的16位字符的头9位是0,则用一个字节表示,这个字节的首位是“0”,剩下的7位与原字符中的后7位相同,如“" u0034”(0000 0000 0011 0100),用“34” (0011 0100)表示;(与源Unicode字符是相同的);

  (2)如果Unicode的16位字符的头5位是0,则用2个字节表示,首字节是“110”开头,后面的5位与源字符中除去头5个零后的最高5 位相同;第二个字节以“10”开头,后面的6位与源字符中的低6位相同。如“"u025d”(0000 0010 0101 1101),转化后为“c99d”(1100 1001 1001 1101);

  (3)如果不符合上述两个规则,则用三个字节表示。第一个字节以“1110”开头,后四位为源字符的高四位;第二个字节以“10”开头,后六位 为源字符中间的六位;第三个字节以“10”开头,后六位为源字符的低六位;如“"u9da7”(1001 1101 1010 0111),转化为“e9b6a7”(1110 1001 1011 0110 1010 0111);

  可以这么描述JAVA程序中Unicode与UTF的关系,虽然不绝对:字符串在内存中运行时,表现为Unicode代码,而当要保存到文件或其它介质中去时,用的是UTF。这个转化过程是由writeUTF和readUTF来完成的。

  好了,基础性的论述差不多了,下面进入正题。

  先把这个问题想成是一个黑匣子。先看黑匣子的一级表示:

input(charsetA)->process(Unicode)->output(charsetB)

  简单,这就是一个IPO模型,即输入、处理和输出。同样的内容要经过“从charsetA到unicode再到charsetB”的转化。

  再看二级表示:

SourceFile(jsp,java)->class->output

  在这个图中,可以看出,输入的是jsp和java源文件,在处理过程中,以Class文件为载体,然后输出。再细化到三级表示:

jsp->temp file->class->browser,os console,db

app,servlet->class->browser,os console,db

  这个图就更明白了。Jsp文件先生成中间的Java文件,再生成Class。而Servlet和普通App则直接编译生成Class。然后,从Class再输出到浏览器、控制台或数据库等。

  JSP:从源文件到Class的过程

  Jsp的源文件是以“.jsp”结尾的文本文件。在本节中,将阐述JSP文件的解释和编译过程,并跟踪其中的中文变化。

  1、JSP/Servlet引擎提供的JSP转换工具(jspc)搜索JSP文件中用<%@ page contentType ="text/html; charset=<Jsp-charset>"%>中指定的charset。如果在JSP文件中未指定<Jsp- charset>,则取JVM中的默认设置file.encoding,一般情况下,这个值是ISO8859-1;

  2、jspc用相当于“javac –encoding <Jsp-charset>”的命令解释JSP文件中出现的所有字符,包括中文字符和ASCII字符,然后把这些字符转换成Unicode字 符,再转化成UTF格式,存为JAVA文件。ASCII码字符转化为Unicode字符时只是简单地在前面加“00”,如“A”,转化为“"u0041” (不需要理由,Unicode的码表就是这么编的)。然后,经过到UTF的转换,又变回“41”了!这也就是可以使用普通文本编辑器查看由JSP生成的 JAVA文件的原因;

  3、引擎用相当于“javac –encoding UNICODE”的命令,把JAVA文件编译成CLASS文件;

  先看一下这些过程中中文字符的转换情况。有如下源代码:

<%@ page contentType="text/html; charset=gb2312"%>
<html><body>
<%
String a="中文";
out.println(a);
%>
</body></html>

  这段代码是在UltraEdit for Windows上编写的。保存后,“中文”两个字的16进制编码为“D6 D0 CE C4”(GB2312编码)。经查表,“中文”两字的Unicode编码为“"u4E2D"u6587”,用 UTF表示就是“E4 B8 AD E6 96 87”。打开引擎生成的由JSP文件转变而成的JAVA文件,发现其中的“中文”两个字确实被“E4 B8 AD E6 96 87”替代了,再查看由JAVA文件编译生成的CLASS文件,发现结果与JAVA文件中的完全一样。

  再看JSP中指定的CharSet为ISO-8859-1的情况。

<%@ page contentType="text/html; charset=ISO-8859-1"%>
<html><body>
<%
String a="中文";
out.println(a);
%>
</body></html>

  同样,该文件是用UltraEdit编写的,“中文”这两个字也是存为GB2312编码“D6 D0 CE C4”。先模拟一下生成的JAVA文件和CLASS文件的过程:jspc用ISO-8859-1来解释“中文”,并把它映射到Unicode。由于ISO -8859-1是8位的,且是拉丁语系,其映射规则就是在每个字节前加“00”,所以,映射后的Unicode编码应为“"u00D6"u00D0" u00CE"u00C4”,转化成UTF后应该是“C3 96 C3 90 C3 8E C3 84”。好,打开文件看一下,JAVA文件和CLASS文件中,“中文”果然都表示为“C3 96 C3 90 C3 8E C3 84”。

  如果上述代码中不指定<Jsp-charset>,即把第一行写成“<%@ page contentType="text/html" %>”,JSPC会使用file.encoding的设置来解释JSP文件。在RedHat 6.2上,其处理结果与指定为ISO-8859-1是完全相同的。

  到现在为止,已经解释了从JSP文件到CLASS文件的转变过程中中文字符的映射过程。一句话:从“JspCharSet到Unicode再到UTF”。下表总结了这个过程:

  表2 “中文”从JSP到CLASS的转化过程
Jsp-CharSet JSP文件中 JAVA文件中 CLASS文件中
GB2312 D6 D0 CE C4(GB2312) 从"u4E2D"u6587(Unicode)到E4 B8 AD E6 96 87 (UTF) E4 B8 AD E6 96 87 (UTF)
ISO-8859-1 D6 D0 CE C4
(GB2312)
从"u00D6"u00D0"u00CE"u00C4 (Unicode)到C3 96 C3 90 C3 8E C3 84 (UTF) C3 96 C3 90 C3 8E C3 84 (UTF)
无(默认=file.encoding) 同ISO-8859-1 同ISO-8859-1 同ISO-8859-1

下节先讨论Servlet从JAVA文件到CLASS文件的转化过程,然后再解释从CLASS文件如何输出到客户端。之所以这样安排,是因为JSP和Servlet在输出时处理方法是一样的。

  Servlet:从源文件到Class的过程

  Servlet源文件是以“.java”结尾的文本文件。本节将讨论Servlet的编译过程并跟踪其中的中文变化。

  用“javac”编译Servlet源文件。javac可以带“-encoding <Compile-charset>”参数,意思是“用< Compile-charset >中指定的编码来解释Serlvet源文件”。

  源文件在编译时,用<Compile-charset>来解释所有字符,包括中文字符和ASCII字符。然后把字符常量转变成Unicode字符,最后,把Unicode转变成UTF。

  在Servlet中,还有一个地方设置输出流的CharSet。通常在输出结果前,调用HttpServletResponse的 setContentType方法来达到与在JSP中设置<Jsp-charset>一样的效果,称之为<Servlet- charset>。

  注意,文中一共提到了三个变量:<Jsp-charset>、<Compile-charset>和< Servlet-charset>。其中,JSP文件只与<Jsp-charset>有关,而<Compile- charset>和<Servlet-charset>只与Servlet有关。

  看下例:

import javax.servlet.*;

import javax.servlet.http.*;

class testServlet extends HttpServlet
{
public void doGet(HttpServletRequest req,HttpServletResponse resp)
throws ServletException,java.io.IOException
{
resp.setContentType("text/html; charset=GB2312");
java.io.PrintWriter out=resp.getWriter();
out.println("<html>");
out.println("#中文#");
out.println("</html>");
}
}

  该文件也是用UltraEdit for Windows编写的,其中的“中文”两个字保存为“D6 D0 CE C4”(GB2312编码)。

  开始编译。下表是<Compile-charset>不同时,CLASS文件中“中文”两字的十六进制码。在编译过程中,< Servlet-charset>不起任何作用。<Servlet-charset>只对CLASS文件的输出产生影响,实际上是 <Servlet-charset>和<Compile-charset>一起,达到与JSP文件中的<Jsp- charset>相同的效果,因为<Jsp-charset>对编译和CLASS文件的输出都会产生影响。

  表3 “中文”从Servlet源文件到Class的转变过程
Compile-charset Servlet源文件中 Class文件中 等效的Unicode码
GB2312 D6 D0 CE C4
(GB2312)
E4 B8 AD E6 96 87 (UTF) "u4E2D"u6587 (在Unicode中=“中文”)
ISO-8859-1 D6 D0 CE C4
(GB2312)
C3 96 C3 90 C3 8E C3 84 (UTF) "u00D6 "u00D0 "u00CE "u00C4 (在D6 D0 CE C4前面各加了一个00)
无(默认) D6 D0 CE C4 (GB2312) 同ISO-8859-1 同ISO-8859-1

普通Java程序的编译过程与Servlet完全一样。

CLASS文件中的中文表示法是不是昭然若揭了?OK,接下来看看CLASS又是怎样输出中文的呢?

Class:输出字符串

上文说过,字符串在内存中表现为Unicode编码。至于这种Unicode编码表示了什么,那要看它是从哪种字符集映射过来的,也就是说要看它的祖先。这好比在托运行李时,外观都是纸箱子,里面装了什么就要看寄邮件的人实际邮了什么东西。

看看上面的例子,如果给一串Unicode编码“00D6 00D0 00CE 00C4”,如果不作转换,直接用Unicode码表来对照它时,是四个字符(而且是特殊字符);假如把它与“ISO8859-1”进行映射,则直接去掉 前面的“00”即可得到“D6 D0 CE C4”,这是ASCII码表中的四个字符;而假如把它当作GB2312来进行映射,得到的结果很可能是一大堆乱码,因为在GB2312中有可能没有(也有 可能有)字符与00D6等字符对应(如果对应不上,将得到0x3f,也就是问号,如果对应上了,由于00D6等字符太靠前,估计也是一些特殊符号,真正的 汉字在Unicode中的编码从4E00开始)。

各位看到了,同样的Unicode字符,可以解释成不同的样子。当然,这其中有一种是我们期望的结果。以上例而论,“D6 D0 CE C4”应该是我们所想要的,当把“D6 D0 CE C4”输出到IE中时,用“简体中文”方式查看,就能看到清楚的“中文”两个字了。(当然了,如果你一定要用“西欧字符”来看,那也没办法,你将得不到任何有何时何地的东西)为什么呢?因为“00D6 00D0 00CE 00C4”本来就是由ISO8859-1转化过去的。
  给出如下结论:

在Class输出字符串前,会将Unicode的字符串按照某一种内码重新生成字节流,然后把字节流输入,相当于进行了一步“String.getBytes(???)”操作。???代表某一种字符集。

如果是Servlet,那么,这种内码就是在HttpServletResponse.setContentType()方法中指定的内码,也就是上文定义的<Servlet-charset>。

如果是JSP,那么,这种内码就是在<%@ page contentType=""%>中指定的内码,也就是上文定义的<Jsp-charset>。

如果是Java程序,那么,这种内码就是file.encoding中指定的内码,默认为ISO8859-1。

当输出对象是浏览器时

以流行的浏览器IE为例。IE支持多种内码。假如IE接收到了一个字节流“D6 D0 CE C4”,你可以尝试用各种内码去查看。你会发现用“简体中文”时能得到正确的结果。因为“D6 D0 CE C4”本来就是简体中文中“中文”两个字的编码。

OK,完整地看一遍。

JSP:源文件为GB2312格式的文本文件,且JSP源文件中有“中文”这两个汉字

如果指定了<Jsp-charset>为GB2312,转化过程如下表。

表4 Jsp-charset = GB2312时的变化过程

序号 步骤说明 结果
1 编写JSP源文件,且存为GB2312格式 D6 D0 CE C4
(D6D0=中 CEC4=文)
2 jspc把JSP源文件转化为临时JAVA文件,并把字符串按照GB2312映射到Unicode,并用UTF格式写入JAVA文件中 E4 B8 AD E6 96 87
3 把临时JAVA文件编译成CLASS文件 E4 B8 AD E6 96 87
4 运行时,先从CLASS文件中用readUTF读出字符串,在内存中的是Unicode编码 4E 2D 65 87(在Unicode中4E2D=中 6587=文)
5 根据Jsp-charset=GB2312把Unicode转化为字节流 D6 D0 CE C4
6 把字节流输出到IE中,并设置IE的编码为GB2312(作者按:这个信息隐藏在HTTP头中) D6 D0 CE C4
7 IE用“简体中文”查看结果 “中文”(正确显示)

如果指定了<Jsp-charset>为ISO8859-1,转化过程如下表。

表5 Jsp-charset = ISO8859-1时的变化过程

序号 步骤说明 结果
1 编写JSP源文件,且存为GB2312格式 D6 D0 CE C4
(D6D0=中 CEC4=文)
2 jspc把JSP源文件转化为临时JAVA文件,并把字符串按照ISO8859-1映射到Unicode,并用UTF格式写入JAVA文件中 C3 96 C3 90 C3 8E C3 84
3 把临时JAVA文件编译成CLASS文件 C3 96 C3 90 C3 8E C3 84
4 运行时,先从CLASS文件中用readUTF读出字符串,在内存中的是Unicode编码 00 D6 00 D0 00 CE 00 C4
(啥都不是!!!)
5 根据Jsp-charset=ISO8859-1把Unicode转化为字节流 D6 D0 CE C4
6 把字节流输出到IE中,并设置IE的编码为ISO8859-1(作者按:这个信息隐藏在HTTP头中) D6 D0 CE C4
7 IE用“西欧字符”查看结果 乱码,其实是四个ASCII字符,但由于大于128,所以显示出来的怪模怪样
8 改变IE的页面编码为“简体中文” “中文”(正确显示)

奇怪了!为什么把<Jsp-charset>设成GB2312和ISO8859-1是一个样的,都能正确显示?因为表4表5中的第2步和第5步互逆,是相互“抵消”的。只不过当指定为ISO8859-1时,要增加第8步操作,殊为不便。

再看看不指定<Jsp-charset> 时的情况。

表6 未指定Jsp-charset 时的变化过程

序号 步骤说明 结果
1 编写JSP源文件,且存为GB2312格式 D6 D0 CE C4
(D6D0=中 CEC4=文)
2 jspc把JSP源文件转化为临时JAVA文件,并把字符串按照ISO8859-1映射到Unicode,并用UTF格式写入JAVA文件中 C3 96 C3 90 C3 8E C3 84
3 把临时JAVA文件编译成CLASS文件 C3 96 C3 90 C3 8E C3 84
4 运行时,先从CLASS文件中用readUTF读出字符串,在内存中的是Unicode编码 00 D6 00 D0 00 CE 00 C4
5 根据Jsp-charset=ISO8859-1把Unicode转化为字节流 D6 D0 CE C4
6 把字节流输出到IE中 D6 D0 CE C4
7 IE用发出请求时的页面的编码查看结果 视情况而定。如果是简体中文,则能正确显示,否则,需执行表5中的第8步

Servlet:源文件为JAVA文件,格式是GB2312,源文件中含有“中文”这两个汉字

如果<Compile-charset>=GB2312,<Servlet-charset>=GB2312

表7 Compile-charset=Servlet-charset=GB2312 时的变化过程

序号 步骤说明 结果
1 编写Servlet源文件,且存为GB2312格式 D6 D0 CE C4
(D6D0=中 CEC4=文)
2 用javac –encoding GB2312把JAVA源文件编译成CLASS文件 E4 B8 AD E6 96 87 (UTF)
3 运行时,先从CLASS文件中用readUTF读出字符串,在内存中的是Unicode编码 4E 2D 65 87 (Unicode)
4 根据Servlet-charset=GB2312把Unicode转化为字节流 D6 D0 CE C4 (GB2312)
5 把字节流输出到IE中并设置IE的编码属性为Servlet-charset=GB2312 D6 D0 CE C4 (GB2312)
6 IE用“简体中文”查看结果 “中文”(正确显示)

如果<Compile-charset>=ISO8859-1,<Servlet-charset>=ISO8859-1

表8 Compile-charset=Servlet-charset=ISO8859-1时的变化过程

序号 步骤说明 结果
1 编写Servlet源文件,且存为GB2312格式 D6 D0 CE C4
(D6D0=中 CEC4=文)
2 用javac –encoding ISO8859-1把JAVA源文件编译成CLASS文件 C3 96 C3 90 C3 8E C3 84 (UTF)
3 运行时,先从CLASS文件中用readUTF读出字符串,在内存中的是Unicode编码 00 D6 00 D0 00 CE 00 C4
4 根据Servlet-charset=ISO8859-1把Unicode转化为字节流 D6 D0 CE C4
5 把字节流输出到IE中并设置IE的编码属性为Servlet-charset=ISO8859-1 D6 D0 CE C4 (GB2312)
6 IE用“西欧字符”查看结果 乱码(原因同表5)
7 改变IE的页面编码为“简体中文” “中文”(正确显示)

如果不指定Compile-charset或Servlet-charset,其默认值均为ISO8859-1。

当Compile-charset=Servlet-charset时,第2步和第4步能互逆,“抵消”,显示结果均能正确。读者可试着写一下Compile-charset<>Servlet-charset时的情况,肯定是不正确的。

当输出对象是数据库时

输出到数据库时,原理与输出到浏览器也是一样的。本节只是Servlet为例,JSP的情况请读者自行推导。

假设有一个Servlet,它能接收来自客户端(IE,简体中文)的汉字字符串,然后把它写入到内码为ISO8859-1的数据库中,然后再从数据库中取出这个字符串,显示到客户端。

表9 输出对象是数据库时的变化过程(1)

序号 步骤说明 结果
1 在IE中输入“中文” D6 D0 CE C4 IE
2 IE把字符串转变成UTF,并送入传输流中 E4 B8 AD E6 96 87
3 Servlet接收到输入流,用readUTF读取 4E 2D 65 87(unicode) Servlet
4 编程者在Servlet中必须把字符串根据GB2312还原为字节流 D6 D0 CE C4
5 编程者根据数据库内码ISO8859-1生成新的字符串 00 D6 00 D0 00 CE 00 C4
6 把新生成的字符串提交给JDBC 00 D6 00 D0 00 CE 00 C4
7 JDBC检测到数据库内码为ISO8859-1 00 D6 00 D0 00 CE 00 C4 JDBC
8 JDBC把接收到的字符串按照ISO8859-1生成字节流 D6 D0 CE C4
9 JDBC把字节流写入数据库中 D6 D0 CE C4
10 完成数据存储工作 D6 D0 CE C4 数据库
以下是从数据库中取出数的过程
11 JDBC从数据库中取出字节流 D6 D0 CE C4 JDBC
12 JDBC按照数据库的字符集ISO8859-1生成字符串,并提交给Servlet 00 D6 00 D0 00 CE 00 C4 (Unicode)  
13 Servlet获得字符串 00 D6 00 D0 00 CE 00 C4 (Unicode) Servlet
14 编程者必须根据数据库的内码ISO8859-1还原成原始字节流 D6 D0 CE C4  
15 编程者必须根据客户端字符集GB2312生成新的字符串 4E 2D 65 87
(Unicode)
 
Servlet准备把字符串输出到客户端
16 Servlet根据<Servlet-charset>生成字节流 D6D0 CE C4 Servlet
17 Servlet把字节流输出到IE中,如果已指定<Servlet-charset>,还会设置IE的编码为<Servlet-charset> D6 D0 CE C4
18 IE根据指定的编码或默认编码查看结果 “中文”(正确显示) IE

解释一下,表中第4第5步和第15第16步是用红色标记的,表示要由编码 者来作转换。第4、5两步其实就是一句话:“new String(source.getBytes("GB2312"), "ISO8859-1")”。第15、16两步也是一句话:“new String(source.getBytes("ISO8859-1"), "GB2312")”。亲爱的读者,你在这样编写代码时是否意识到了其中的每一个细节呢?

至于客户端内码和数据库内码为其它值时的流程,和输出对象是系统控制台时的流程,请读者自己想吧。明白了上述流程的原理,相信你可以轻松地写出来。

行文至此,已可告一段落了。终点又回到了起点,对于编程者而言,几乎是什么影响都没有。

因为我们早就被告之要这么做了。

以下给出一个结论,作为结尾。

1、 在Jsp文件中,要指定contentType,其中,charset的值要与客户端浏览器所用的字符集一样;对于其中的字符串常量,不需做任何内码转 换;对于字符串变量,要求能根据ContentType中指定的字符集还原成客户端能识别的字节流,简单地说,就是“字符串变量是基于<Jsp- charset>字符集的”;

2、 在Servlet中,必须用HttpServletResponse.setContentType()设置charset,且设置成与客户端内码一致; 对于其中的字符串常量,需要在Javac编译时指定encoding,这个encoding必须与编写源文件的平台的字符集一样,一般说来都是 GB2312或GBK;对于字符串变量,与JSP一样,必须“是基于<Servlet-charset>字符集的”。

posted @ 2008-01-17 14:34 backup2007 阅读(504) | 评论 (0)编辑 收藏

编码问题2转

Jsp页面使用URL编码传递中文参数的情况下,在参数的解析过程中会出现乱码。由于 java在设计的时候考虑到了国际化的问题,在java源程序编译成字节码的时候默认使用的是UTF-8编码。而在web运用上,由于不同的浏览器向服务 器发送的信息采用的编码方式不同,在由像tomcat之类的服务器解码的时候会由于编码方式的不同而产生乱码,这是一个会困扰jsp初学者很久的问题。以 前在使用struts的时候不需要处理这些问题,前些天在做一个简单的jsp页面的时候碰到这个问题。经过半天的摸索,基本解决了该问题。
例子中a.jsp页面通过URL编码的方式传递中文参数,在b.jsp中对该参数进行解析。
a.jsp源代码
<%@ page contentType="text/html; charset=gb2312" language="java" import="java.sql.*" errorPage="" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>无标题文档</title>
</head>
 
<body>
<% 
       String str_test = "华工";
%>
<form method=post action="b.jsp?test=<%=java.net.URLEncoder.encode(str_test) %>"> 
         <input type="submit" value="Submit" name="提交">  
 </form>
 
</body>
</html>
 
b.jsp源代码
<%@ page contentType="text/html; charset=gb2312" language="java" import="java.sql.*" errorPage="" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>无标题文档</title>
</head>
 
<body>
 
<%
       String str = new String(request.getParameter("test").getBytes("ISO8859_1"));
%> 
 <BR>
 <%=str %>
</body>
</html>
说明:在使用了java.net.URLEncoder.encode 编码后,页面获取参数request.getParameter后需要使用ISO8859_1编码转换。此外,在jsp的字符集声明中把charset=UTF-8也没有问题

posted @ 2008-01-17 14:30 backup2007 阅读(205) | 评论 (0)编辑 收藏

编码问题1 转

     摘要: HTML:     ……     //实际上这里的charset=utf-8 也是可以的,因为在中文平台下     //用了GB2312     JS:     我用了两个方法提交:GET 和 POST。 ...  阅读全文

posted @ 2008-01-17 14:29 backup2007 阅读(539) | 评论 (0)编辑 收藏

2007年12月24日 #

vim 常用命令 转

1、vim颜色太暗,默认的尤其是注释颜色太暗,根本看不清,可通过下述方式设置
:colorscheme evening

2、vim以16进制方式编辑文件:
:%!xxd

3、用vim格式化代码
从别的编辑器里粘贴到vim里的代码经常由于不正常的缩进变得格式混乱,有如下两种方式:
格式化全文: gg=G
自动缩进当前行: ==

4、vim退出后在
屏幕上保留被编辑文件的内容:
:set t_ti= t_te=

5、多文件编辑
打开多个文件:vim a.c b.c b.c
切换到下一文件:n
切换到另一文件:e <文件名如b.c>
返回上一文件: e#

横向分屏:split (不加参数为分屏当前文件,加文件名为以分屏方式打开另一文件)
竖向分屏:vsplit,与split不同之处在于竖向分屏
分屏后切换:ctrl+两次按w

6、删除内容到缓冲区
x为删除光标当前字符,而X则删除光标前字符;
dd为删除当前行;
nx,nX,ndd则表明删除的数目;

7、拷贝内容到缓冲区
yy,为拷贝当前行到缓冲区;
yw,为拷贝单个词到缓冲区;
nyy,nyw则表明拷贝的数目;

8、移动到某一行:
: n,n为行号

nG,n为行号

9、visual编辑
三种进入方式:
v ---- 以字符为单位进行选择
V ---- 以行为单位进行选择
ctrl+v ---- 以列块方式进行选择
ctrl+c ---- 退出visual编辑方式

进入后对选择进行的操作有:
d --- 删除
y --- 复制
> --- 右移4格
< --- 左移4格
~ --- 大小写切换
U --- 变成大写
u --- 变成小写

posted @ 2007-12-24 18:33 backup2007 阅读(714) | 评论 (0)编辑 收藏

quote : installnation of eclipse for java

1. 下载文件
JDK    jdk-1_5_0_06-linux-i586-rpm.bin  http://java.sun.com
eclipse    eclipse-SDK-3.1.2-linux-gtk.tar.gz  http://www.eclipse.org
CDT    org.eclipse.cdt-3.0.2-linux.x86.tar.gz  http://www.eclipse.org/cdt

2. 安装JDK

chmod +x jdk-1_5_0_06-linux-i586-rpm.bin
./jdk-1_5_0_06-linux-i586-rpm.bin

设置环境变量,编辑/etc/profile,在下面加入

export JAVA_HOME=/usr/java/jdk1.5.0_06
export PATH=$JAVA_HOME/bin:$PATH
CLASSPATH=.:/usr/java/jdk1.5.0_06/lib/tools.jar:$CLASSPATH
export CLASSPATH

3. 安装eclipse

tar -zxvf eclipse-SDK-3.1.2-linux-gtk.tar.gz

再移动到想要的目录中,这里为/opt
编写一个执行脚本,内容如下:

#eclipse
#
export JAVA_HOME=/usr/java/jdk1.5.0_06
export CLASSPATH=/usr/java/jdk1.5.0_06/lib
/opt/eclipse/eclipse -vm /usr/java/jdk1.5.0_06/bin/java -data ~/workspace &

cp eclipse.sh /usr/local/bin
chmod 755 /usr/local/bin/eclipse.sh

将eclipse.sh 添加到桌面。桌面上按下鼠标右键,在弹出菜单中选择“创建启动器”,在“名称”中输入Eclipse、“命令”中填 /usr/local/bin/eclipse.sh,按“确定”,桌面上就有eclipse的快捷方式了,以后可以直接双击这个图标启动 Eclipse。

4. 安装CDT

tar -zxvf org.eclipse.cdt-3.0.2-linux.x86.tar.gz

将相映目录中的文件cp到eclipse目录中





---------------------

先要在linux下安装好jre,我的jre的安装目录是/usr/java/jre1.5

把下载的文件解压即可:

#tar -zxvf eclipse-SDK-3.2-linux-gtk.tar.gz(可以加上绝对路径)

3 为让每个用户都可以执行Eclipse,编写Eclipse.sh脚本:

#!/bin/bash

#

#exe eclipse3.2

#

/usr/eclipse/eclipse -vm /usr/java/jre1.5/bin/java -data ~/workspace &

# -vm 参数用以指定使用哪一个 jvm 来执行Eclipse

# -date参数用以指定Eclipse的数据目录。在此指定其存在用户根目录(~)下的workspace目录中

eclipse.sh 复制到/usr/local/bin中,并为它加上权限755;现在执行 eclipse.sh 即可启动 Eclipse

4桌面上建立快捷方式:

在桌面上按下鼠标右键,在弹出菜单中选择“新增启动”,之后分別在“名称”中输入Eclipse3.2,“命令”中填 /usr/local/bin/eclipse.sh,然后再为它随便找个喜欢的图标(我用的是/opt/eclipse/icon.xpm;再后按“确定”,桌面上就有eclipse的快捷方式了,以后可以直接双击这个图标启动Eclipse

posted @ 2007-12-24 17:21 backup2007 阅读(296) | 评论 (0)编辑 收藏

转 eclipse3.3 + minGW for c/c++ development

本设置的主要目的是在最新版的eclipse3.3(Europa)上开发标准C/C++程序,而不去使用VC++。

因为CDT只提供了开发C/C++项目的IDE,所以我们需要安装MinGW(即 Minimalist GNU For Windows。它是一些头文件和端口库的集合,该集合允许人们在没有第三方动态链接库的情况下使用 GCC(GNU Compiler C)产生 Windows32 程序。)和MSYS(Minimal GNU(POSIX)system on Windows,是一个小型的GNU环境,包括基本的bash,make等等。是Windows下最优秀的GNU环境。):
下载Automated MinGW Installer:MinGW-5.1.3.exe(注意这只是个在线安装程序),执行MinGW-5.1.3.exe;
在choose package向导页,选择Current项;
在choose components向导页,选中MinGW base tools和g++ compiler项;
在choose install location向导页,设置安装目录,为说明方便,这里假设路径为d:\MinGW;
等待MinGW在线安装完成。
接下来,在下载MinGW的同一页面,我们下载MSYS (Minimal System):Current Release: msys-1.0.10,执行MSYS-1.0.10.exe;
在安装MSYS过程中,假定我们安装路径为D:\msys;
在安装MSYS过程中,会出现控制台界面(类DOS窗口)的三个询问,分别键入y、y、D:/MinGW(MinGW安装路径)即可。
安装好MinGW和MYYS后,需要配置一下系统的环境变量,右键点击“我的电脑”->属性->高级->环境变量,在系统变量中进行如下操作:
编辑PATH变量,在开头处加入D:\MinGW\bin;D:\msys\1.0\bin;
添加LIBRARY_PATH变量,值为D:\MinGW\lib
添加C_INCLUDE_PATH变量,值为D:\MinGW\include
添加CPLUS_INCLUDE_PATH变量,值为D:\MinGW\include\c++\3.4.2;D:\MinGW\include\c++\3.4.2\mingw32;D:\MinGW\include\c++\3.4.2\backward;D:\MinGW\include
打开系统开始菜单->附件->命令提示符,在里面输入make –version或gcc –version并回车,如果出现版本信息,则配置成功。
如果你的系统上没有安装jre,去下载最新版的jre5.0,并进行安装。
接下来这步,我们先进入到http://www.eclipse.org/downloads/页面,最好直接下载Eclipse IDE for C/C++ Developers - Windows (62 MB) 这个版本,基本上下载完后就可以正常使用。

如果你已经有了eclipse3.3但需要单独安装CDT4的话,请参见这里CDT Europa Releases Update Site,里面说的很清楚,可以在eclipse的help->Software Updates -> Find and Install -> Search for new Features to Install中,加入一个site http://download.eclipse.org/tools/cdt/releases/europa升级即可。

值得注意的是,不要直接下载cdt-master-4.0.0.zip,并且解压缩后覆盖到eclipse目录下!,否则虽然可以调出CDT界面,但编译和执行会有问题。

最后,我们启动eclipse并进行一个测试,创建一个C++ Project,选择Executable->Hello World C++ Project,toolchain选择MinGW GCC。创建后build它即可。

posted @ 2007-12-24 11:51 backup2007 阅读(1268) | 评论 (0)编辑 收藏

2007年12月13日 #

bootSect.S 文件中的include小问题

在 Linux 启动过程中,最开始加载的程序就是 bootSect.S 文件.

其中第一行是一个include 语句:#include <asm/boot.h>
而当我去查看boot.h的时候,发现它的真正位置在 "include/asm-i386/boot.h" 而不是 "include/ asm/boot.h"

这让我很不解,查网上资料也没有解答, 打开makefile文件,仔细看了一下,终于找到原因:

在makefile 中有这么一段:

symlinks:
    rm 
-f include/asm
    ( cd include ; ln 
-sf asm-$(ARCH) asm)
    @if [ 
! -d include/linux/modules ]; then 
        mkdir include
/linux/modules; 
    fi

很明显,首先删除了 asm文件夹,然后 在include 下面做了一个软连接: ln -sf asm-$(ARCH)  asm

这里的ARCH明显是系统相关的环境变量了,比如在i386机器上就是代表i386了。这样asm-i386就转成了asm.

posted @ 2007-12-13 18:23 backup2007 阅读(380) | 评论 (0)编辑 收藏

2007年12月12日 #

putty 登陆unix-center ubuntu服务器 输入中文

putty 登陆unix-center ubuntu服务器默认是无法输入中文的,
服务器上的ubuntu默认是GBK字符集,
把putty 的font改成宋体,chinese_GB2312字符集,
transition 里面保留默认Use font encoding 。
重新登陆即可。

登陆 solaris 服务器我还没找到输入中文的方法。

[在~/ 建立.profile 建立环境变量]

posted @ 2007-12-12 14:10 backup2007 阅读(769) | 评论 (0)编辑 收藏

2007年10月15日 #

J2ee 程序员 需要了解的Linux知识

版权声明:如有转载请求,请注明出处:http://blog.csdn.net/yzhz

         一般大型J2EE应用都在建构在linux环境下的。开发环境下我们可以通过samba映射成本地的网络驱动器,直接在windows环境下进行编程调 试。但是最后的发布还是要到linux环境,同时我们对网上web服务器和数据库服务器的应用管理(比如自动脚本发布等),应用监控(web服务是否正 常、mysql数据库的使用情况)、系统监控(监控磁盘空间的使用情况等)都要求程序员熟悉必要的linux知识。
        当然程序员不必对整个linux系统样样精通。下面根据本人开发的经验,列出程序员基本需要掌握的linux知识。

一、linux的基本命令
1、用户管理
userdel    删除用户帐号
useradd    增加用户账号
su         改变当前用户的ID

2、文件目录管理
ls         浏览目录,查看当前目录下的文件和文件名
chmod      修改文件权限
chown      改变文件所有者
cp         复制文件
cd         改变当前目录
mv         重命名文件或移动文件
rm         删除文件或者目录
pwd        当前目录
scp        远程拷贝
alias      别名

3、其他命令
ln         在文件之间建立链接
tail       输出文件内容后面的部分,一般我们会通过tail -f 实时查看当前程序打印的日志。
type       查看一个命令所在路径
wc         查看行数
grep       在文件内容中查找
find       查找文件
date       查看日期
crontab     制定计划任务,通常用于系统监控。
df          查看磁盘剩余空间,你最好在crontab中写个脚本监控磁盘的空间。超过90%就给相关的人员发email。
ps          查看进程状态
top         查看CPU的使用率
kill        终止进程
killall     java程序员最喜欢用killall -9 java吧
w           查看登录用户和他们正在做什么,也可以看看系统的load。load太高,就该找找原因了。
who         查看当前用户的便当情况
tar         解压或压缩文件
echo        控制台输出
wget        http访问
rpm         rpm包管理

4、重定向、管道
5、标准输出、标准错误
6、使用"屏蔽一个特殊字符的含义
7、正则表达式

二、熟练掌握vim编辑器。

三、liunx环境下shell脚本、perl脚本的编写
为了对网上服务器应用进行管理,通常需要编写一些脚本。
脚本的编写重点掌握下面几点:
1、理解双引号、单引号、反引号的含义。
2、反斜线的使用。
3、shell脚本赋值语句左边的变量名不要加上$,常写perl脚本的常犯此错误。
4、字符串比较长,含有空格的时候,作为一个参数时脚本出错,用双引号把字符串括起来。
5、掌握好awk和sed的用法。

四、基本软件包的安装
apache、resin、mysql
一般的步骤就是:
configure
make
make install

五、相关网站
下面的网站是比较优秀的linux网站,可以去看看。
http://www.linuxforum.net/



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=198050

posted @ 2007-10-15 18:11 backup2007 阅读(413) | 评论 (0)编辑 收藏

2007年10月14日 #

debian JDK安装小记

网上不外乎两种方法,一个是用deb包的,确实方便,一个是用传统方法的,更加通用。
我两个都试过,但是在传统方式安装中遇到了小问题,记录一下。

网上的教程说,修改/etc/profile 添加环境变量,但是这个变量在重新开启终端之后就失效了,每次重新登录后都会失效,
必须用 $source /etc/profile 加载才能生效。
baidu了一下,发现/etc/profile是系统环境变量,在它之前会先加载用户目录下的.bashrc文件,那么我作修改:
在~/.bashrc末尾添加  source /etc/profile ,然后$source ~/.bashrc 使之生效,这样以后重新打开终端也可生效了。
OK.

posted @ 2007-10-14 16:24 backup2007 阅读(903) | 评论 (0)编辑 收藏

仅列出标题  下一页