Thursday, June 19, 2008

RedHat Ubuntu python Mysql MySQLdb mantis+subversion

这几天搞subversion+mantis整合的事情,折腾的一天,目前貌似前进了一步,至少可能遇到的问题应该都被解决了。 将版本控制系统和缺陷管理系统整合起来是一件很值得的事情,通过整合,可以将需求和最终的实现形成一条可追踪的线, 而不是一些离散的软件开发活动。 我们可以分析用例,进行概要设计,并且将软件实现分解成较少工作量的任务,这些东西可以通过在缺陷管理系统中file一个总体的bug,说明要实现的是什么东西,然后每个分解的任务file一个bug,这些bug依赖于那个描述总体的bug。这种方式扩展了缺陷管理系统的概念,应该把它叫做制品管理系统,因为在这个系统中不再只有bug这一个概念,还包括了feature,enhancement,task等。 :(,觉得表达的有些混乱。
下面说说整个整合的过程。
一开始从网上找了文档,有专门说subversion和mantis怎么整合的,看了看,觉得大概没问题,因为我以前也在linux下配过不少东西,mysql, bugzilla,subversion,apache等,所以想事情应该不会太困难。
事实是实际的开发环境和文档中讲的不一样,几乎所有的文档中说的都是mantis和subversion都运行在linux上,这样subversion可以通过ssh来无交互地直接执行mantis机器上的命令。问题是,我们的mantis是跑在window上的。 妈妈的,我尝试在window上装了个windosshd,然后从linux下可以通过密码的方式访问mantis的机器,但是rsa(不需要输入密码)就怎么也不行,openssh本身不太懂。实在搞不定,后来想就直接在subversion的机器上用python来访问mantis的mysql数据库得了,这也行的通,何况我最近一直学习python,正好小试牛刀。

python访问mysql需要MySQLdb的库,我需要在subversion那台机器上安装这个库。 因为我一直用ubuntu,所以直接‘sudo apt-get install mysql-server', 居然提示我没有这个命令,有点昏。后来一查,subversion的机器是redhat enterprise linux4.4的,只好去MySQLdb的网站下载targz的包。 这个包是需要编译的,但是编译过程中总是提示找不到mysql头文件(mysql_config.h),这样看来我需要安装mysql了。
跑到mysql的网站上下载了redhat enterprise linux4的mysql4.1.22的rpm包,结果安装这个包的过程中总是提示文件冲突,烦死了,而且rpm包里面并没有要求的mysql_config.h文件。在后来我就下载了一个mysql的linux下的通用包,48M,这次好了,这个包里面是完整的mysql-server的目录,哈哈,看来要爽一回。
进入MySQLdb的安装目录,需要修改site.cfg文件,设定mysql_config到下载的这个mysql-server目录,即$mysql_server_home/bin, 这次执行python setup.py build就成功了。
mysql_config 是mysql的一个工具,可以查看mysql的很多编译安装信息,所以很多需要mysql头文件来编译的项目都会使用这个工具。在ubuntu下,这个工具要单独安装。
在控制台执行命令:
$python
>>> import MySQLdb
没有报错,安装成功,接下来就是写python代码了
--------------------------------
现在又碰到了中文编码的问题,由于svn提交的时候指定中文消息,这些消息被mantis显示出来的时候全是乱码。后来总算找到办法了,原来需要进行'中文'.decode('utf-8').encode('gbk'),但是subversion那台机器上的python是2.3的,没有中文解码包,需要安装python-cjkcodecs。 python2.4就自带这个包了。妈的!

Thursday, May 22, 2008

MoinMoin......

这些天在做一个Research,就是接下来的一个项目的技术选型,最终这些东西都汇总到一个openoffice的文档中。但是我越来越不喜欢这种写文档的方式,首先这些office的文档都是二进制的,对搜索引擎不友好,更重要的是,我觉得写文档和软件开发一定程度上是由共性的,就是说是一个迭代和增量的过程,需要不断的反馈,需要集体的协作。我想要的写文档的方式应该是多个人一起完成初稿,然后所有的相关人员都可以来浏览,来编辑,来提意见,就是wikipedia的方式,当然一个专职的文档维护人员(或者一个维护委员会)是必须的,由他来最终确定哪些修改是好的,哪些意见是应该被抛弃的。最后,文档应该是公开的,易于查看,相关文档应该彼此链接,不应该藏在svn的某个深深的角落。
WikiWiki可以解决这个问题,我觉得可以一个主要编写人员首先列出提纲,然后每个部分都有专业的人员来编写,而这个文档随时任何相关人员都可以查看,可以提意见,最终依靠集体的力量完成文档。传统的方式都是一个人完成文档,然后组织大家一起来讨论,然后继续修改,继续讨论。这种方式的效率不高,这要求审核人员必须在特定的时间段里去阅读文档,进行讨论,而审核人员到底付出多大的精力去阅读这篇文档很重要。就目前的经历来看,审核人员通常都不会在这件事情上花多少力气,所以审核的质量非常低。通过wiki的方式,大家可以更深刻的参与到文档的编写工作中来,每个人都随时可以查看文档的进度,可以添加注释,可以直接修改。
下面就说说wiki系统的安装,因为我决心要学习python,所以专门找了一个python的wiki系统,MoinMoin,很多大型网站都采用了这个wiki系统,尤其开源网站,它们更有动力采用wiki来促进社区的交流。

操作系统:Ubuntu 7.10 Desktop, linux kernel 2.6.22-14-generic
Python : 2.5.1
WebServer: lighttpd 1.4.18 (ssl)
MoinMoin: 1.6.3

::安装过程可以查看MoinMoin发布包中自带的Install.html
1. 确认python和lighttpd都已经安装成功。 一般来说ubuntu系统已经自带了python,而安装lighttpd也非常简单,执行'sudo apt-get install lighttpd'就可以了。
  • 在控制台执行'python', 出现python提示符'>>>'就表示python已经安装成功了。
  • 执行'lighttpd -D -f /etc/lighttpd/lighttpd.conf', 然后在浏览器中访问'http://localhost',看到html页面就表示lighttpd安装成功了。
2.下载MoinMoin, 解压缩发布包之后,进入安装文件目录,在控制太执行安装命令:
>>>python setup.py install --prefix='/usr/local' --record=install.log
其中, --prefix表示安装目标目录,如果不指定,那么会安装到默认目录,通常是/usr/lib/python2.5/site-pakcage/moin和/usr/share/moin; --record表示安装日志,可以从中看出哪些文件被copy到哪个目录了。
NOTE:更多信息可以参考moinmoin的install.html
3. ....关于moin的配置请参考moinmon的install.html
4. 配置FasgCGI。如果CGI方式,那么每个请求相应的cgi文件都会被重新load,这样会极大的影响的性能, 而FastCGI方式只需要在第一次请求的时候load脚本,然后这些脚本就会被缓存下来,这样可以大大提高性能,此外,FasgCGI是一个单独运行的网关进程,就算webserver崩溃也不会影响到它。在多核的环境下,FastCGI是个不错的选择。mod_python是运行在webserver中的一个线程,在超线程的环境下可能表现更好。lighttpd不支持mod_python。
lighttpd是一个高性能的,轻型的(相较与apache),高度模块化的webserver,它需要在配置文件lighttpd.conf中指定装载fcgi模块,并且配置fcgi相应的参数。
note: 可以参考install.html中的'deploying in lighttpd'
  • 设定装入fcgi模块:
    server.modules              = (
    "mod_access",
    "mod_rewrite", # <--- IMPORTANT! "mod_status", "mod_fastcgi", # <--- IMPORTANT! "mod_accesslog", "mod_redirect", "mod_auth", "mod_expire", )
  • 配置fasgcgi模块,
    $HTTP["host"] =~ "^127.0.0.1" {
    url.rewrite-once = (
    "^/robots.txt" => "/robots.txt",
    "^/favicon.ico" => "/favicon.ico",
    "^/moin_static163/(.*)" => "/$1", #所有的media文件url都是以moin_static163开头的
    "^/(.*)" => "/wiki-engine/$1" #除了media文件和robots,favicon外的请求都送到fastcgi server
    )
    server.document-root = "/usr/share/moin/htdocs/"
    #url以wiki-engine开始的都送到fastcgi。 url会被rewrite模块重写,可以看前面的定义url.rewrite-once
    $HTTP["url"] =~ "^/wiki-engine/" {
    fastcgi.server = ( "/wiki-engine" =>
    (( "docroot" => "/",
    "min-procs" => 10,
    "max-procs" => 10,
    "max-load-per-proc" => 2,
    # allocate successive port numbers for each process, starting with "port"
    "bin-path" => "/opt/mylib/moin-1.6.3/moin.fcg", #如果由lighttpd来启动fastcgi,那么需要指定这个值
    "host" => "127.0.0.1",
    "port" => 3060,
    "check-local" => "disable",
    ))
    )
    }
    }
一般来说,由于指定了bin-path参数,所以lighttpd会自动启动一个fastcgi进程,不需要额外的在外面手动启动一个fastcgi进程。 如果没有指定,那么需要手动在外面启动fastcgi进程,同时保证指定的host,port与fastcgi server的定义是一致的。 lighttpd和fastcgi server之间通过tcp socket通信,也可以直接通过unix-domain socket(IPC socket,进程间通信)通信,这个需要指定fastcgi.server的socket参数,host+port和socket只能采用一种。
5.这里反过来再提一下MoinMoin的配置。我的MoinMoin是安装到默认目录,即/usr/lib/python2.5/site-package/moin和/usr/share/moin,前面一个目录放置的是moinmoin的python源代码, /usr/share/moin放置的是模板代码(html,img,css等)和数据文件(保存用户数据,比如page, comments,user等)。然后我又把/usr/share/moin中的data, underlay,wikiconfig.py, moin.fcg复制到/opt/mylib/moin目录,这个目录叫做MoinMoin的一个实例。就是说你可以同时运行多个实例,它们分别有自己的名称空间,彼此不会影响,但是共用htdocs。
此外,需要注意的是权限问题,由于lighttpd是以www-data的用户运行,而fastcgi程也是它启动的,即fastcgi server也是以www-data的用户运行的,那么www-data必须具有/opt/mylib/moin目录读写执行权限。 总之要注意权限问题。但是如果fastcgi是通过手动单独在外面启动的,那么启动这个进程的用户必须具有读写执行/opt/mylib/moin的权限,这样的话,它是独立与lighttpd的权限系统之外的,可以另外设置权限规则。

Thursday, May 15, 2008

我的兴趣真是广泛......咳咳

对于我的职业规划,我一直是想做一名架构师,因为本身有对于技术的持续的热情和学习动力。而且兴趣广泛对于一名架构师来说应该算是优势,作为架构师保持宽阔的眼界应该是很重要的。 但是有时候在这些兴趣之间会有些迷失,而且热点变化的过快,导致了贪多嚼不烂。 比如这段时间, 由于工作上相对比较清闲,所以可以去看很多东西,包括document software architecture, agile development(scrum), python(jython), osgi, maven, flex,跨度可以说是相当的大,的确是开阔了眼界,但是沉淀的不多, 也许面试的时候到可以满口的胡说八道,让人目眩神迷。
我想是需要计划了, 应该给这些东西排个优先级别,然后各个击破,当然不是每个都要精通,比如flex(个人来说,我觉得这是比ajax更有前途的东西),就是所谓的divide and conquer。下面就列一下吧, 优先级从1-5,1便是优先级最高:
  1. document software architecture: 最切合职业规划.....P1
  2. agile development: 敏捷开发,其实还包括up,xp等......P2
  3. python:作为一个程序员,至少得会两门语言,这是我的要求.....P2
  4. flex: ria技术,相信比ajax更有前途.....P3
虽然flex的有限级别最低,但是我刚刚下载了flex sdk, 怎么说呢,现在等不及要尝试一下了。
.......
经过短暂的狂热,并且下载了flex_sdk_3,阅读了一些开发文档之后,狂热劲似乎慢慢消逝了。怎么说呢,flex框架包含了大量的漂亮的ui组件,而且对开放标准的支持也不错,比如使用css来定义组件外观,用mxml语言来定义界面,actionscript来定义逻辑,这种设计对程序员来说更加友好,毕竟让一个程序员来进行那种基于时间帧的设计有点牵强。我相信可以使用flex构建出炫目的应用,但是有一点,我觉得非常不足,就是flex与浏览器的整合太弱了,这里说的整合不是说浏览器是否都安装了flash插件这个问题,而是说flash与浏览器之间的互操作性,以及与html的dom模型之间的互操作性, flash虽然是运行在浏览器中,但是它们显然是两个世界的东西, 这让我觉得不太舒服, 可能我们以前使用浏览器的操作习惯在面对flash的时候都变的不一样,这可能会让人们困惑,从这个角度讲,我开始更倾向于ajax了。

Friday, May 09, 2008

读书笔记:Document software architecture

在读一本书,不是教你如何做架构设计,而是如果将系统架构记录下来,但这对架构设计还是很有帮助的,因为你知道了如何文档化一个系统架构,就说明你知道了架构应该包含哪些元素,应该从什么角度来描述架构,这真的很重要,是一种thinking层次的东西,比仅仅会技术还要带劲。
这篇博客是用来作为我的读书笔记, 英文文档已经看完了,但是有些部分太晦涩,用了太多不认识的单词,看的头晕,现在又弄了中文版来对照看。 中文版翻译的一般,有些地方我需要回过去看英文。

[architecture]
什么是架构???
A software architecture for a system is a structure of the system, which comprise elements, relation among them, and the external visible properties of those elements and relations.


[view]

[viewtype]

[style]

[如何描述架构?]
Architects need to
think about their software in three ways simultaneously(同时,一起):
1. How it is structured as a set of implementation units (module viewtype)
2. How it is structured as a set of elements that have runtime behavior and interactions(component-and-connector viewtype)
3. How it relates to nonsoftware structures in its environment (allocation viewtype)

咳咳,先做个记号,有空才写!

Thursday, May 08, 2008

关于字符(characters),字符集(character sets), 编码(encodings)

在程序中我们经常要处理字符的编码转换,比如两个系统之间传输包含中文字符的信息时候,或者向数据库存储/读取中文数据的时候,你都会碰到这个问题。对于缺乏经验的程序员,这是个烦恼和郁闷的问题。 起码我是经受过这样的反复折磨,每个项目都会碰到这个问题,而每次解决了之后还是觉得若有所示,因为我不清楚为什么这样就解决了,虽然我一直是这样解决这个问题的。 所以我期望把这个问题搞清楚,我希望知道为什么错,有为什么对。。。。

[字符,字符集,编码]

字符, 呵呵,就是字符,比如a,b,c,或者汉字的'我'.
字符集(比如unicode)定义了一种编码规范支持哪些字符,每个字符都会被分配一个编码(或者说整数,以免和后面要说的编码混淆,后面说的编码应该是一个动词),通过这个编码就可以映射到相应的字符. 在不同的字符集中,同一个字符的编码一般是不一样的.
而编码(比如utf-8)是定义了如何将这些字符保存在内存或者文件等。 GBK字符集包括2万多个汉字,每个字符都有一个码,编码就是如何将这些码保存下来。 unicode有些不同,因为unicode为每个字符定义了code point,编码标准,比如utf-8, ucs-2,定义了如何将code point保存下来。

[存在的编码方法]

这里说的编码方式不仅仅只中文,还包括其他,相信俄文,印度文等等都会有自己的类似gbk一类的编码标准。下面只列出我知道的,比较常用的编码方式:
  • ASCII: American Standard Code for Information Interchange, 这是英文字符的编码,使用了单字节,ASCII的最高bit位都为0,从0-127。
    ASCII码是7位编码,编码范围是0x00-0x7F。ASCII字符集包括英文字母、阿拉伯数字和标点符号等字符。其中0x00-0x20和0x7F共33个控制字符。

    只支持ASCII码的系统会忽略每个字节的最高位,只认为低7位是有效位。HZ字符编码就是早期为了在只支持7位ASCII系统中传输中文而设计的编码。早期很多邮件系统也只支持ASCII编码,为了传输中文邮件必须使用BASE64或者其他编码方式。
  • Latin-1(ISO-8859-1): 这是欧洲的编码,因为西欧语言中包含很多字符,比如á这种字符。它是ASCII的超集,那些古怪字符用的是128-255的范围,利用单字节存储。
  • Unicode(www.unicode.org):这是一个想要大一统的编码标准,要为世界上每种语言的每个字符都定义一个编码。它又是Latin-1的超集,用两个字节存储。当然不可能是所有字符,其实是语言的常用字符,比如汉字编码的范围是4e00-9fcf,大概2万个左右,不会包含古老的甲骨文汉字。 unicode是一个字符集,它有许多不同的编码方式,比如UCS-2是直接用两个自己来存储,而utf-16也是用两个自己存储,而utf-8是变长的,对0-127之间的用单个字节,128以上的用两个,三个甚至6个字节来表示。(CHECK:??字节的最高位第八位用来表示这个字符是单字节还是双字节
  • GBK:这是中国定义的汉字编码标准,最早是GB2312,只定义了常用汉字,大概2万个左右(unicode主要包含gb2312中的汉字),后来的gbk是对gb2312的扩展,加入了很多不常用的汉字,同时也支持了繁体字。中文字符的每个字节的最高位都为1。 在中国大陆使用的计算机上,它们的本地编码(ANSI编码)大多都是gbk。在一个国家的本地化系统中出现的一个字符,通过电子邮件传送到另外一个国家的本地化系统中,看到的就不是那个字符了,而是另个那个国家的一个字符或乱码。(http://www.btinternet.com/~jlonline/back/GBK.htm)
    GB2312是基于区位码设计的,区位码把编码表分为94个区,每个区对应94个位,每个字符的区号和位号组合起来就是该汉字的区位码。区位码一般 用10进制数来表示,如1601就表示16区1位,对应的字符是“啊”。在区位码的区号和位号上分别加上0xA0就得到了GB2312编码。

  • UTF-8: 首先 UCS 和 Unicode 只是分配整数给字符的编码表. 现在存在好几种将一串字符表示为一串字节的方法. 最显而易见的两种方法是将 Unicode 文本存储为 2 个 或 4 个字节序列的串. 这两种方法的正式名称分别为 UCS-2 和 UCS-4. 除非另外指定, 否则大多数的字节都是这样的(Bigendian convention). 将一个 ASCII 或 Latin-1 的文件转换成 UCS-2 只需简单地在每个 ASCII 字节前插入 0x00. 如果要转换成 UCS-4, 则必须在每个 ASCII 字节前插入三个 0x00.

    在 Unix 下使用 UCS-2 (或 UCS-4) 会导致非常严重的问题. 用这些编码的字符串会包含一些特殊的字符, 比如 '\0' 或 '/', 它们在 文件名和其他 C 库函数参数里都有特别的含义. 另外, 大多数使用 ASCII 文件的 UNIX 下的工具, 如果不进行重大修改是无法读取 16 位的字符的. 基于这些原因, 在文件名, 文本文件, 环境变量等地方, UCS-2 不适合作为 Unicode 的外部编码.

    在 ISO 10646-1 Annex R 和 RFC 2279 里定义的 UTF-8 编码没有这些问题. 它是在 Unix 风格的操作系统下使用 Unicode 的明显的方法.

    UTF-8 有以下特性:

    *UCS 字符 U+0000 到 U+007F (ASCII) 被编码为字节 0x00 到 0x7F (ASCII 兼容). 这意味着只包含 7 位 ASCII 字符的文件在 ASCII 和 UTF-8 两种编码方式下是一样的.
    *所有 >U+007F 的 UCS 字符被编码为一个多个字节的串, 每个字节都有标记位集. 因此, ASCII 字节 (0x00-0x7F) 不可能作为任何其他字符的一部分.
    *表示非 ASCII 字符的多字节串的第一个字节总是在 0xC0 到 0xFD 的范围里, 并指出这个字符包含多少个字节. 多字节串的其余字节都在 0x80 到 0xBF 范围里. 这使得重新同步非常容易, 并使编码无国界, 且很少受丢失字节的影响.
    *可以编入所有可能的 231个 UCS 代码
    *UTF-8 编码字符理论上可以最多到 6 个字节长, 然而 16 位 BMP 字符最多只用到 3 字节长.
    *Bigendian UCS-4 字节串的排列顺序是预定的.
    *字节 0xFE 和 0xFF 在 UTF-8 编码中从未用到.

    下列字节串用来表示一个字符. 用到哪个串取决于该字符在 Unicode 中的序号.
    U-00000000 - U-0000007F: 0xxxxxxx
    U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
    U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
    U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
    U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

    xxx 的位置由字符编码数的二进制表示的位填入. 越靠右的 x 具有越少的特殊意义. 只用最短的那个足够表达一个字符编码数的多字节串. 注意在多字节串中, 第一个字节的开头"1"的数目就是整个串中字节的数目.

    例如: Unicode 字符 U+00A9 = 1010 1001 (版权符号) 在 UTF-8 里的编码为:

    11000010 10101001 = 0xC2 0xA9

    而字符 U+2260 = 0010 0010 0110 0000 (不等于) 编码为:

    11100010 10001001 10100000 = 0xE2 0x89 0xA0

    这种编码的官方名字拼写为 UTF-8, 其中 UTF 代表 UCS Transformation Format. 请勿在任何文档中用其他名字 (比如 utf8 或 UTF_8) 来表示 UTF-8, 当然除非你指的是一个变量名而不是这种编码本身.

[编码转换]
实际上不存在什么编码转换地概念, 当你用什么编码方式写出的时候, 读入就应该用同样的编码方式,否则乱码就来找你了.先看下面一个例子:


String input = "S茅n茅gal";
System.out.println(HexCoder.bufferToHex(input.getBytes("GBK")));
>>53c3a96ec3a967616c
System.out.println(HexCoder.bufferToHex(input.getBytes("UTF-8")));
>>53e88c856ee88c8567616c
String utf8 = new String(input.getBytes("GBK"), "UTF-8");
System.out.println(utf8);
>>Sénégal

可以看到GBK和UTF8得到的字节数组是不一样的,有趣的是最有的变量'utf8',它的内容是法文'Sénégal', 而初始的变量'input'才是乱码.这个转换其实容易理解, input.getBytes('GBK')会得到'53c3a96ec3a967616c', 而用utf-8的方式来解码的话,就得到了'Sénégal'.这个例子让我们觉得乱码和原文之间可以互相转换, 某种程度上说是这样的.
但是, 再看看下面的例子:


String input = "我";
System.out.println(HexCoder.bufferToHex(input.getBytes("GBK")));
>>ced2
System.out.println(HexCoder.bufferToHex(input.getBytes("UTF-8")));
>>e68891
String utf8 = new String(input.getBytes("GBK"), "UTF-8");
System.out.println(utf8);
>>??
System.out.println(HexCoder.bufferToHex(utf8.getBytes("GBK")));
>>3f3f
System.out.println(HexCoder.bufferToHex(utf8.getBytes("UTF-16")));
>>fefffffdfffd
* feff is Unicode Byte Order Mark.

这个例子和第一个例子只有变量input的值不同, 但是可以看到变量utf8.getBytes("GBK")最后打印出来是??, 为什么? input.getBytes("GBK")后得到了ced2, 当用UTF8来解码的时候,utf8完全无法识别这个编码,所以用?(\ufffd, 不是问号\u003f)表示. 而最后一句'utf8.getBytes("GBK")', 打印出来的也就是3f3f(3f就是ascii中的?, 因为gbk的字符集中没有和\ufffd对应的字符)了.

还有一个问题,java中的字串是unicode, 这句话到底什么意思? 看下面的例子:
System.out.println("\u0048\u0065\u006C\u006C\u006F");
>>Hello
这里0048是字符H的unicode的code point,和编码(就是如何保存这个字串在内存/磁盘或者在网络中传输)没有关系.

It does not make sense to have a string without knowing what encoding it uses
[内码外码]
所谓内码就是指的gbk,unicode的编码,而外码指的是输入法中定义的字码,外码是可以随便定义,而内码是不能变的,输入法会映射外码到内码。

这里还是要强调需要搞清楚字符,字符集,编码的区别, 可以认为GBK的字符集和编码定义的值都是一样的.
看看在java中的表现.
char c = '甜';
System.out.println(Integer.toHexString((int)c));
// print out: 751c, 打印出来'甜'的unicode的codepoint(就是说在jvm内部是以codepoint(unicode字符集定义了每个字符的codepoint)来表示一个uncode字符。但是当需要和其他系统交换这个字符的时候,就需要采用编码规则来将字符编码成字节), 这
//也说明为什么我们总是说java中的字符都是unicode的. 也就是说,JVM内存中, 所有的字符都是以unicode的UTF16编码形式表示的
byte[] output = src.getBytes("UTF-8");
for (byte o : output){
System.out.println(Integer.toHexString(o));
}
// print out:
// ffffffe7
// ffffff94
// ffffff9c

output = src.getBytes("GBK");
for (byte o : output){
System.out.println(Integer.toHexString(o));
}
// print out:
// ffffffcc
// fffffff0
// 为什么能得GBK的编码值呢? java提供了一个CharsetDecoder的类用来执行这种转换(每一个charset都会有一个
// 对应的子类), 估计应该是首先从UTF16的编码得到unicode字符集的code point, 然后在unicode的字符集和
// gbk的字符集之间有一个映射(估计操作系统会管理这个映射,或者JVM自己管理,这个不是重点),最后对这个GBK的code point进行GBK编码.
// 就是说,字符集是不同编码之间进行转换的桥梁.

output = src.getBytes("UTF-16");
for (byte o : output){
System.out.println(Integer.toHexString(o));
}
// print out:
// fffffffe
// ffffffff
// 75
// 1c
// Java2平台内对unicode采用UTF16的编码方式, 这种编码方式GBK的特点, 编码出来的值和code point是一样的
// (只是指unicode的BMP部分:U+0000 - U+FFFF). 对大于U+FFFF的字符会用四个字节来进行编码,具体的可以参考
// UTF16编码规范. 为什么'tian'在utf16编码后会有四个字节呢????

更多信息可以参考:
  • 字符,字节和编码:http://www.regexlab.com/zh/encoding.htm
  • GBK, http://www.btinternet.com/~jlonline/back/GBK.htm
  • 字符编码笔记(

    http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html)
  • The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (http://www.joelonsoftware.com/articles/Unicode.html)