??xml version="1.0" encoding="utf-8" standalone="yes"?>
今晚用到 ByteBuffer, 我跟 joy 都是初学 java, 文档里的中文译实在是看他母亲不? 晕了半天, 作了几个试, l于把这个类的用法搞清楚? Z臆想了哈其工作原?
// ...
//
// 此段代码功能Z t.txt 里复制所有数据到 out_j.txt:
//
...
1 FileChannel fcin = new FileInputStream( "d:/t.txt" ).getChannel();
2 FileChannel fcout = new FileOutputStream( new File( "d:/out_j.txt" )).getChannel();
3 ByteBuffer buff = ByteBuffer.allocate( 1024 );
4 long t1 = System.currentTimeMillis();
5
6 while( fcin.read( buff ) != -1 )
7 {
8 buff.flip();
9 fcout.write( buff );
10 buff.clear();
11 }
12
13 long t2 = System.currentTimeMillis();
14 long size = fcin.size();
15 javax.swing.JOptionPane.showMessageDialog( null, size + " 字节, 耗时 " + ( t2 - t1 + 1 ) + " ms." );
...
----------------------------------------------------------------------------------------------------
SDK 文档里对 ByteBuffer 的说明ؓ:
public abstract class ByteBuffer
extends Buffer
implements Comparable <ByteBuffer>
q说?ByteBuffer 是承于 Buffer 的抽象类, 实现了两个接?
? 通过 allocate() 分配了一?1024 字节的缓冲区, q返回一?ByteBuffer 对象. (抽象cM能直?new)
? fcin.read() 数据读入到 buff. 此处?read() ?FileChannel cȝ一个虚函数.
? buff.flip() q个调用是开头一直无法理解的部分.
----------------------------------------------------------------------------------------------------
SDK 文档里的?flip() 的说明是:
public final Buffer flip()
反{
我最l的理解? 文档译得太差了, 把不应该译的内容也译成了中? 所以反而不Ҏ理解.
关键在以下 2 ?
当前位置
限制
反{
q个{背后的操作其实就?"?endPointer 定位?curPointer ? q把 curPointer 设ؓ 0".
关于标记, 在这里不涉及. 下一句说到常?compact Ҏ一起? 是可以想像的, 因ؓ compact ҎҎ据进
行了压羃, 有效数据的真实长度发生了变化, 肯定需要用 flip 重新定位l束标记.
在填? 压羃{数据操作时, curPointer 估计都是自动更新了位|的, L指向最后一个有效数? 所以每ơ调
?flip() ? endPointer 指向了有效数据的结? ?curPointer 指向?0 (~冲起始?.
(c ?e 分别代表 curPointer ?endPointer 两个指针)
* 先是一个空?ByteBuffer (大小?10 字节)
-------------------
-------------------
c
e
* 然后填充 5 字节数据
-------------------
0 1 2 3 4
-------------------
e c
此时, endPointer 在 0 ? curPointer Ud了数据结?
l测? 此时若取数据, 得?5 个字? 内容通常?0 (也有可能是未?, 因ؓ实际上取到的是从 c 处到~冲
* 调用一?flip() ?/span>
-------------------
0 1 2 3 4
-------------------
c e
此时, endPointer 先被Ud curPointer, 然后 curPointer Ud 0.
通过试可见, ByteBuffer 取数据时, 是从 curPointer ? ?endPointer ? ?curPointer > endPointer, 则取到缓冲区l束.
再看上面代码的关键片D? ?8 处调?flip() x两个作用, 一是将 curPointer Ud 0, 二是?endPointer Ud有效数据l尾.
此行可由以下两行代替:
buff.limit( buff.position());
buff.position( 0 );
可见对其工作原理的理? 应该是正的.
----------------------------
1. put 数据? 不会自动清除~冲Z现有的数?
2. 每一?get ?put ? curPointer 都将向缓冲区NUd, Ud?操作的数据量.
3. get/put 均是?curPointer ? ?curPointer + 操作的数据长度止.
4. get/put 操作? ?curPointer 过?endPointer 或缓冲区总长? 抛?java.nio.BufferUnderflowException 异常.
? curPointer ?endPointer 只是为文中方便描q命名的, 实际分别对应?ByteBuffer.position() ?ByteBuffer.limit() 两个Ҏ.
----------------------------------------------------------------------------------------------------
curPointer 是用 ByteBuffer.position() 取? ?ByteBuffer.position( int ) 赋? 不知?JDK Z么要用多态来实现q两个功? 按我的想? 设计?getPosition(), setPosition() 不是要好看好记得多啊.
----------------------------------------------------------------------------------------------------
C++ 里面没有cM ByteBuffer 的现成实? 实现上述cM的文件复制功? 通常要自己创?/span>理~冲? C++ 里读写文仉常?FileRead(), FileWrite() 函数, 在读/写的时? 可以直接指定?写的数据长度, 相比下显?/span>
直观方便? ?JDK q个 ByteBuffer 的方? 实更方便好?
ByteBuffer 作ؓl承?Buffer 的抽象类, 实现了对 Byte 型缓冲的理, 同时 JDK 里还有对应其他数据类型的
l承?Buffer 的抽象类, 分别实现对应cd的缓冲管? q种设计减少了编E时的工? 如果?C++ ? 调用
?写函数时, q需要考虑传入数据的类? 通常用传?sizeof(数据cd) 的方式指? 除了函数调用时增加?/span>
费外, 灉|性也更差?
反过来再? Z?C 要用q种方式? 个h认ؓ, q是 C 标准库的实现方式, 因ؓ在不?OS q_? Ҏ件和
讑֤的访问方法在pȝ层不一定相? 同时gq_(主要?CPU)上基本数据类型宽度也有可能不? 标准库通过
sizeof q个宏在~译时才能确定数据宽? 所以标?C 代码通常可以在不同^C重新~译.
再想 C++ Z么要用这U方? 首先, C++ 里沿?C 标准库的模式是可以理解的, 其次, 也许只是 C++ 标准?/span>
里没有类似的设计, 说不定早有W三斚w过模板实现的了.
个h认ؓ, ByteBuffer 在实C, 可以是一U数据结? 在类设计? 可以是一U设计模式了.
]]>
]]>
据个例子Q书上说inverse=falseӞ׃控方l持关系。。?br style="line-height: normal; " /> ׃我也是初学者。。。再加上语文水^偏低。。。不理解“l持关系是啥意?#8221;囧~
提示Q?br style="line-height: normal; " /> (1)如果Q您不了解Hibernate的one-to-many或many-to-one的概c?/span>
(2)如果Q你不了解Hibernate?#8220;自由?#8221;“持久?#8221;“游离?#8221;的概c?/span>
(3)如果Q您不了解Hibernate中的“脏数?#8221;的概c?/span>
(4)如果Q您对Hibernate中Session~存Q没有初步了解的话?br style="line-height: normal; " /> (在Hibernate中调用saveq行存储数据的时?q不是马上就Ҏ据库q行insert操作Q而是会将?#8220;数据对象(vo)”U_Hibernate的Session~存?
在上面的4条提CZQ如果您对其中的某一条,不是很清楚的话。希望请先了解有关知识?br style="line-height: normal; " /> 否则Q可能您?“无法或很?#8221;理解 cascade ?inverse q?个属性?/span>
首相Qcascade ?inverse q两个属性,其实是完全不同的两个东西Q想要了解他们各自的“用途与区别”Q详见如下介l:
q里有两个表:
Q?Qclass (班?
相应字段Q?br style="line-height: normal; " />
cid varchar(32) 主键 not-null (班id)
cname varchar(16) not-null (班名称)
Q?Qstudent (学生?
相应字段Q?br style="line-height: normal; " />
sid varchar(32) 主键 not-null (学生id)
sname varchar(16) not-null (学生姓名)
class_id varchar(32) not-null (学生所属班U?
一个班U?class)对应多个学生(student)Q所以班U表(class)是“one-to-many”?br style="line-height: normal; " /> 反之student是many-to-one
//--------Classcȝ代码--------
public class Class implements.....
{
private cId = "";
private cName = "";
private students = java.util.HashMap();
// 省略对应?geter setter
}
//--------Class.hbm.xml--------
<hibernate-mapping>
<class name="lcx.vo.Class" table="class"
catalog="demo">
<id name="cid" type="java.lang.String">
<column name="cid" length="32" />
<generator class="uuid.hex" />
</id>
<property name="name" type="java.lang.String">
<column name="cname" length="16" not-null="true" />
</property>
<set name="students" table="student" cascade="save-update">
<key column="class" />
<one-to-many class="lcx.vo.Student" />
</set>
</class>
</hibernate-mapping>
//--------Studentcȝ代码;*******
public class Student implements.....
{
private sId = "";
private sName = "";
private Class class = null;
// 省略对应?geter setter
}
// Student.hbm.xml
<hibernate-mapping>
<class name="lcx.vo.Student" table="student" catalog="demo">
<id name="cid" type="java.lang.String">
<column name="sid" length="32" />
<generator class="uuid.hex" />
</id>
<many-to-one name="class"
class="lcx.vo.Class"
column="class_id"
not-null="true"
/>
</class>
</hibernate-mapping>
Q一Q?cascade 的介l:
当Hibernate持久化一?#8220;临时对象(也叫自由态对?”Ӟ在默认的情况?卻I没有讄cascade属性或cascade=none?QHibernate不会自动“持久化他所兌”的其他时对象?/span>
上面q些话是什么意思呢Q?什么叫不会自动 “持久?#8221;兌的时对象呢Q?/span>
看如下代码:
// 创徏一?临时对象(也叫自由态对?
// 也就是说q个 class 没有被HibernateU_Session~存理?br style="line-height: normal; " />
Class class = new Class();
//class.id 动生?br style="line-height: normal; " />
class.setName("一q1?);
Student stu = new Student();
//student.id 动生?br style="line-height: normal; " />
stu.setName("白?);
stu.setClass(class);
// 关键是q里。。?br style="line-height: normal; " /> class.getStudents().add(stu);
session.save(class);
// 提交
// 注意: Class.hbm.xml文g?cascade="save-update"q且也没有设|inverse属?也就是说inverse=false;
// 此时如果你开启了Hibernate的显CHQL语句功能Q那么控制台会昄如下3条HQLQ?/span>
//----------------------------------------********
insert into demo.class (cid, cname) values (66666666666666666666666666666666, 一q1?
insert into demo.student (sid,sname,class_id) values (8888888888888888811cb2e04c888888, 白? 66666666666666666666666666666666)
update demo.student set class_id=66666666666666666666666666666666 where sid=8888888888888888811cb2e04c888888
//----------------------------------------********
那么Z么会出现Q这3条HQL语句呢,我们来一一分析一下:
W?条HQL语句:
其实W一条HQL比较好理解,
当我们调?session.save(class) 后,在Hibernateq行提交的时候,
会发?#8220;?#8221;一?#8220;?#8221;的数据要插入(insert)Q所以就往class表中,插入了这条新的class记录?/span>
W?条HQL语句Q?br style="line-height: normal; " /> 注意问题在q里Q?br style="line-height: normal; " /> q里Z么又出现了一条insert语句呢?而且q是向student表中插入数据?br style="line-height: normal; " /> 我们在上面的代码中,q没有编写类?#8220;session.save(student)”q样的语句啊?br style="line-height: normal; " /> q是Z么呢Q?br style="line-height: normal; " /> 其实原因Q是q么回事Q因为我们在class端,讄?U联更新"(?cascade="save-update")Q?br style="line-height: normal; " /> 也就是说Q当Hibernate在向class表中插入“?#8221;对象记录Ӟ会检?#8220;Class对象”所兌的属?是<set>对应的属?Q是否发生过变化Q如果发生了变化Q就按照“U联属?cascade)”所讑֮的内?br style="line-height: normal; " /> q行操作?/span>
上面讲的q句话到底是什么意思呢Q?br style="line-height: normal; " />
用你?#8220;?#8221;话说Q就是:
因ؓ调用?class.getStudents().add(stu);
所以,在Hibernate在进行插?class对象的时候,发现class对象Q所兌的集合中Q有一?br style="line-height: normal; " />
“自由?#8221;的对象,而又因ؓclass端设|了“U联属性cascade”Q所以,在插入这?“新class对象”Ӟ也一同把他内部的那些Q还属于“自由?#8221;的其他对象,也一同插入到Q他们所对应的表中去了?/span>
q是不明白的话。。。可以看看。孙卫琴的《精通Hibernate》,在书上的W?49|?br style="line-height: normal; " /> 但是关于inverse的介l。。。写的就有些书面化了Q如果语文不好的话。。。就难懂咯~
W?条HQL语句Q?br style="line-height: normal; " />
W三条HQL语句是一条update语句Q是不是觉得Q很莫名其妙。。。?br style="line-height: normal; " />
Hibernate大脑q水了吧Q怎么吃饱了撑得,重复更新记录啊啊啊啊?br style="line-height: normal; " />
假如Q我们把 class端的配置文档中的 invser属性设|ؓtrue(卻Iinverse=true)
在执行上面的E序Q发玎ͼ变?条insert语句啦。。。。?update没啦。。?
看来W三条的update语句和inverse有着密切的关p(他两有一腿~Q?/span>
所以我们下边,来介绍一下inverse属?
当调?Class.getStudents().add(stu)ҎQ进行添加操作时Q?nbsp;
(卻I?"q个Class对象"所属的“集合 (也就是调用getStudentsҎ所q回的那个Set集合)”中添加一个Student(?add(stu))Q也是_q个“?#8221;d的Student对象(stu)Q?nbsp;
他的Student.class_id字段“必须”Q要{于“被添加方Class”的主??Class.cid)?nbsp;
?#8220;数据?#8221;层面来讲Q也是_q个“?#8221;d?#8220;Student”的class_id字段Q必要?#8220;Class”的cid字段Q存?d键关??
正因为如此:所以Hibernate“?#8221; 在进?"Class.getStudents().add(stu)" q样的操作时Q?nbsp;
出现意外情况(? stu.getClass=nullQ即Qstu没有所属班U?Q?br style="line-height: normal; " />
?#8220;d?#8221;(Student)?#8220;被添加方”(Class)Q存?#8220;外键”不一致的情况发生?nbsp;
所以就出现?那条多余的update语句。即Qone-to-manyQClass端)dȝ护Child.Class_id
所以就是说QHibernate怕出错,q你多执行一ơ无用的更新语句Q以保证 add ?Class“集合”中的所有Student
都是要与Class有外键关联的?/span>
用普通话说就?
一q??getStudents().add(白?;
一q??getStudents().add(大白?;
也就是说现在不管?白?q是 大白?nbsp;
如果他们Q目前还没有自己的班U的话,
一q?班的班主d会主动邀请他们成Zq?班的同学啦~?/span>
也就是说 一q?班的班主?d邀?同学Q而不?同学自己来~~~ 所以效率也降低了。。。?/span>
所以我们一般把 一对多?invser讄为trueQ即Q不让主控端ȝ护主键关联,
Q即Q让同学自己L班Q?br style="line-height: normal; " />
说白了,是Qone-to-many端不用去理 “新添加对?#8221; 的主外键U束问题?/span>
把one-to-many端(?class?的invser讄为true
(卻I每次向class.getStudentsq个集合中添?studentӞ不去dupdate对应的外?Q?br style="line-height: normal; " />
而是在student端去手动讄
例如Q?br style="line-height: normal; " />
student.setClass(class);
session.save(student);
q样手动讄 student与class兌啦。。。?br style="line-height: normal; " />
所以上面的E序“最?#8221;q是写成q样Q?/span>
Class class = new Class();
class.setName("一q1?);
session.save(class);
Student stu = new Student();
stu.setName("白?);
stu.setClass(class);
session.save(class);
/*
此时向class集合add内容Q不会进行数据库操作(update)?br style="line-height: normal; " />
“更新”的只是session~存中,数据镜像?br style="line-height: normal; " />
q样做的好处是:不仅减少了update语句Q?br style="line-height: normal; " />
而且Q同时也更新了session~存?br style="line-height: normal; " />
------------------------
而在原来:
one-to-many端inverse=falseӞ虽然也更新seesion~存中的class集合Q?br style="line-height: normal; " />
但是有却又多余update
*/
class.getStudents().add(stu);
// 提交
ȝ:
当inverse=false q且向one-to-many端的兌集合Q添?#8220;新对?? 自由态对?” Ӟ
Hibernate׃自动Q去update?#8220;个刚刚到来的” “自由态对?#8221;的外键?br style="line-height: normal; " />
Q如果你向,one-to-many端添的集合中Qadd一?#8220;已经持久化了的对?#8221;Q那׃会出现update?因ؓ已经持久化过?Q除非,你去 更改“那个持久化对?#8221;所对应的外键。。。那L话。。。呵呵呵~~~
你可以试一试,应该不会报错Q你可以当做l习d一下,加深cascade和inverseq两个属性的理解Q?/span>
// 如果看懂了上面的内容。来看一下,下面的东ѝ?br style="line-height: normal; " />
假如Q将one-to-many??Class??hbm.xml 文档中的cascadeU除?或把cascade="none"?br style="line-height: normal; " />
那么上面的代码会出现什么情况呢?br style="line-height: normal; " />
l果会出?条HQLQ和一堆Exception
insert into demo.class (cid, cname) values (66666666666666666666666666666666, 一q1?
update demo.student set class_id=66666666666666666666666666666666 where sid=8888888888888888811cb2e04c888888
Hibernate Exceptinon......................................
相比较cascade被设|?save-update"的时候,~少??insert语句Q而且也多了一些Exception?/span>
那么Q到底是了?条insert语句呢?
是q条Q?br style="line-height: normal; " />
insert into demo.student (sid,sname,class_id) values (8888888888888888811cb2e04c888888, 白? 66666666666666666666666666666666)
之所以会出现Q这L现象Q想必您已经早就看出来了?br style="line-height: normal; " /> 因ؓQ我没有讄Class端的CascadeQ所以在save(class)的时候,q没有自动将其所兌?#8220;自由态对?#8221;q行持久化操作?br style="line-height: normal; " /> 然而,又因?Class端的inverse=falseQ所以,Class会自动去l持Q那?“新来的student” 的外键?br style="line-height: normal; " /> 所以会出现Q没有insertpupdate啦。。。?br style="line-height: normal; " /> 然后在就是Exception?/span>
术语 |
说明 |
备注 |
Screen sizeQ屏q尺? |
指的是手机实际的物理寸Q比如常用的2.8英寸Q?.2英寸Q?.5英寸Q?.7英寸 |
摩托|拉milestone手机?.7英寸 |
Aspect Ratio(宽高比率) |
指的是实际的物理寸宽高比率,分ؓlong和nolong |
Milestone?6Q?,属于long |
Resolution(分L? |
和电脑的分L率概念一P指手机屏q纵、横方向像素个数 |
Milestone?54*480 |
DPI(dot per inch) |
每英寸像素数Q如120dpi,160dpi{?假设QVGA(320*240)分L率的屏幕物理寸是(2英寸*1.5英寸Q,dpi=160 |
可以反映屏幕的清晰度Q用于羃放UI?/span> |
Density(密度) |
屏幕里像素值浓度,resolution/Screen size可以反映出手机密?/span> |
|
Density-independent pixel (dip) |
指的是逻辑密度计算单位,dip和具体像素值的对应公式是dip/pixel=dpi?160 |
|
|
Low density (120), ldpi |
Medium density (160), mdpi |
High density (240), hdpi |
Small screen |
QVGA (240x320) |
|
|
Normal screen |
WQVGA400 (240x400)WQVGA432 (240x432) |
HVGA (320x480) |
WVGA800 (480x800)WVGA854 (480x854) |
Large screen |
|
WVGA800* (480x800)WVGA854* (480x854) |
|
单位Q像?/span>
WVGA854: 854*480
QVGA: 320*240
WQVGA400Q?00*240
1.开发环境工具选用Jdk1.5 + ActivePerl-5.6 + S60_5th_Edition_SDK_v1_0+ Carbide.C++.V2.3
JDK1.5 下蝲的地方很多,׃提供了?/p>
ActivePerl-5.6 下蝲地址Qftp://ftp.activestate.com/ActivePerl/Windows/5.6/ActivePerl-5.6.1.635-MSWin32-x86.msi
S60_5th_Edition_SDK_v1_0下蝲地址Q?a target="_blank">http://sw.nokia.com/id/577ad48d-290c-4bb5-8bdf-779ea8a5bc6c/S60_5th_Edition_SDK_v1_0_en.zip
Carbide.C++.V2.3下蝲地址Q?a target="_blank">http://www.forum.nokia.com/info/sw.nokia.com/id/dbb8841d-832c-43a6-be13-f78119a2b4cb.html
安装步骤如下Q?/p>
1、在C盘中建立一个文件夹Q如 SymbianApp
2、安装jdk到该目录?/p>
3、安装ActivePerl-5.6到该目录下,安装q个Perl的时候,要注意,如果曄在系l中装过oracle10GQ那么会出现? H,oracle10G中自带了一个ActivePerl 5.8版本的,在环境变量中 Path中可以找到相应的路径Q需要把5.8版本的\径从环境变量中删除,否则会造成q行出错Q无法编译?/p>
4、安装S60_5th_Edition_SDKQ这里要注意了,安装到SymbianAppq个目录下的时候, 该SDK默认的安装地址? C:\Program Files\S60\devices\S60_5th_Edition_SDK_v1.0Q要改ؓc:\SymbianApp \S60_5th_Edition_SDK_v1.0,q么改的目的Q尽量让q个sdk模拟器的路径短好Q一长串的后果,是模拟器一打开q接关 闭?/p>
5、安装Carbide.C++.V2.3
按照上述步骤做完Q有可能会出玎ͼCarbide.C++中没有配|默认的sdk包,需要在软g中手动设|?/p>
再后来,他们又做了一些可以处理这些字节的机器Q机器开动了Q可以用字节来组合出很多状态,状态开始变来变厅R他们看到这h好的Q于是它们就q机器称?计算??br />
开始计机只在国用。八位的字节一共可以组合出256(2?ơ方)U不同的状态?nbsp;
他们把其中的~号?开始的32U状态分别规定了Ҏ的用途,一但终端、打印机遇上U定好的q些字节被传q来Ӟp做一些约定的动作。遇?0x10, l端换行,遇上0x07, l端向Z嘟嘟叫,例如遇上0x1b, 打印机就打印反白的字Q或者终端就用彩色显C字母。他们看到这样很好,于是把q些0x20以下的字节状态称?控制??nbsp;
他们又把所有的I格、标点符受数字、大写字母分别用连l的字节状态表C,一直编CW?27Pq样计算机就可以用不同字节来存储p的文字了。大?看到q样Q都感觉很好Q于是大安把这个方案叫?ANSI ?Ascii"~码QAmerican Standard Code for Information InterchangeQ美国信息互换标准代码)。当时世界上所有的计算机都用同LASCIIҎ来保存英文文字?nbsp;
后来Q就像徏造巴比u塔一P世界各地的都开始用计机Q但是很多国家用的不是英文,他们的字母里有许多是ASCII里没有的Qؓ了可以在计算Z存他 们的文字Q他们决定采?27号之后的IZ来表C些新的字母、符Pq加入了很多画表格时需要用下到的横Uѝ竖Uѝ交叉等形状Q一直把序号~到了最后一 个状?55。从128?55q一늚字符集被U?扩展字符?。从此之后,贪婪的hcd没有新的状态可以用了,帝国主义可能没有想到还有第三世界国 家的Z也希望可以用到计机吧!
{中国h们得到计机Ӟ已经没有可以利用的字节状态来表示汉字Q况且有6000多个常用汉字需要保存呢。但是这难不倒智慧的中国人民Q我们不客气地把那些127号之后的奇异W号们直接取消掉,
规定Q一个小?27的字W的意义与原来相同,但两个大?27的字W连在一hQ就表示一个汉字,前面的一个字节(他称之ؓ高字节)?xA1用到 0xF7Q后面一个字节(低字节)?xA1?xFEQ这h们就可以l合出大U?000多个体汉字了。在q些~码里,我们q把数学W号、罗马希腊的 字母、日文的假名们都~进MQ连?ASCII 里本来就有的数字、标炏V字母都l统重新~了两个字节长的~码Q这是常说?全角"字符Q而原来在127号以下的那些叫"半角"字符了?nbsp;
中国人民看到q样很不错,于是把q种汉字Ҏ叫做 "GB2312"。GB2312 是对 ASCII 的中文扩展?nbsp;
但是中国的汉字太多了Q我们很快就发现有许多人的人名没有办法在这里打出来Q特别是某些很会ȝ别h的国安gh。于是我们不得不l箋?GB2312 没有用到的码位找出来老实不客气地用上?nbsp;
后来q是不够用,于是q脆不再要求低字节一定是127号之后的内码Q只要第一个字节是大于127固定表C是一个汉字的开始,不管后面跟的是不是扩展字 W集里的内容。结果扩展之后的~码Ҏ被称?GBK 标准QGBK 包括?GB2312 的所有内容,同时又增加了q?0000个新的汉字(包括J体字)和符受?nbsp;
后来数民族也要用电脑了Q于是我们再扩展Q又加了几千个新的少数民族的字,GBK 扩成了GB18030。从此之后,中华民族的文化就可以在计机时代中传承了?nbsp;
中国的程序员们看到这一pd汉字~码的标准是好的Q于是通称他们叫做 "DBCS"QDouble Byte Charecter Set 双字节字W集Q。在DBCSpd标准里,最大的特点是两字节长的汉字字符和一字节长的英文字符q存于同一套编码方案里Q因此他们写的程序ؓ了支持中文处 理,必须要注意字串里的每一个字节的|如果q个值是大于127的,那么pZ个双字节字符集里的字W出C。那时候凡是受q加持,会编E的计算机僧?们都要每天念下面q个咒语数百遍:
"一个汉字算两个英文字符Q一个汉字算两个英文字符……"
因ؓ当时各个国家都像中国q样搞出一套自q~码标准Q结果互怹间谁也不懂谁的编码,谁也不支持别人的~码Q连大陆和台湾这样只盔R?50里Q?着同一U语a的兄弟地区,也分别采用了不同?DBCS ~码Ҏ——当时的中国人想让电脑显C汉字,必装上一?汉字pȝ"Q专门用来处理汉字的昄、输入的问题Q但是那个台湄愚昧徏人士写的命E序 必d装另一套支?BIG5 ~码的什?倚天汉字pȝ"才可以用Q装错了字符pȝQ显C就会ؕ了套Q这怎么办?而且世界民族之林中还有那些一时用不上电脑的穷苦h民,他们的文字又?么办Q?/p>
真是计算机的巴比伦塔命题啊!
正在q时Q大天加百列及时出C——一个叫 ISOQ国际标谁化l织Q的国际l织军_着手解册个问题。他们采用的Ҏ很简单:废了所有的地区性编码方案,重新搞一个包括了地球上所有文化、所有字?和符L~码Q他们打叫?Universal Multiple-Octet Coded Character Set"Q简U?UCS, 俗称 "UNICODE"?nbsp;
UNICODE 开始制订时Q计机的存储器定w极大地发展了Q空间再也不成ؓ问题了。于?ISO q接规定必ȝ两个字节Q也是16位来l一表示所有的字符Q对于ascii里的那些“半角”字符QUNICODE 包持其原~码不变Q只是将光度由原来?位扩展ؓ16位,而其他文化和语言的字W则全部重新l一~码。由?半角"英文W号只需要用C8位,所以其?8位永q是0Q因此这U大气的Ҏ在保存英文文本时会多费一倍的I间?/p>
q时候,从旧C会里走q来的程序员开始发C个奇怪的现象Q他们的strlen函数靠不住了Q一个汉字不再是相当于两个字W了Q而是一个!是的Q从 UNICODE 开始,无论是半角的英文字母Q还是全角的汉字Q它们都是统一?一个字W?Q同Ӟ也都是统一?两个字节"Q请注意"字符"?字节"两个术语的不 同,“字节”是一?位的物理存贮单元Q?#8220;字符”则是一个文化相关的W号。在UNICODE 中,一个字W就是两个字节。一个汉字算两个英文字符的时代已l快q去了?nbsp;
从前多种字符集存在时Q那些做多语a软g的公叔R上过很大ȝQ他们ؓ了在不同的国安售同一套YӞ׃得不在区域化软g时也加持那个双字节字W集?语,不仅要处处小心不要搞错,q要把Y件中的文字在不同的字W集中{来{厅RUNICODE 对于他们来说是一个很好的一揽子解决ҎQ于是从 Windows NT 开始,MS 机把它们的操作pȝ改了一遍,把所有的核心代码都改成了?UNICODE 方式工作的版本,从这时开始,WINDOWS pȝl于无需要加装各U本土语apȝQ就可以昄全世界上所有文化的字符了?nbsp;
但是QUNICODE 在制订时没有考虑与Q何一U现有的~码Ҏ保持兼容Q这使得 GBK 与UNICODE 在汉字的内码~排上完全是不一LQ没有一U简单的术Ҏ可以把文本内容从UNICODE~码和另一U编码进行{换,q种转换必须通过查表来进行?nbsp;
如前所qͼUNICODE 是用两个字节来表CZؓ一个字W,他d可以l合?5535不同的字W,q大概已l可以覆盖世界上所有文化的W号。如果还不够也没有关p,ISO已经准备 了UCS-4ҎQ说单了是四个字节来表CZ个字W,q样我们可以组合出21亿个不同的字W出来(最高位有其他用途)Q这大概可以用到银河联邦成立 那一天吧Q?br />
UNICODE 来到Ӟ一起到来的q有计算机网l的兴vQUNICODE 如何在网l上传输也是一个必考虑的问题,于是面向传输的众?UTFQUCS Transfer FormatQ标准出CQ顾名思义QUTF8是每次8个位传输数据Q而UTF16是每次16个位Q只不过Z传输时的可靠性,从UNICODE?UTF时ƈ不是直接的对应,而是要过一些算法和规则来{换?/p>
受到q网l编E加持的计算机僧侣们都知道,在网l里传递信息时有一个很重要的问题,是对于数据高低位的解读方式Q一些计机是采用低位先发送的ҎQ例 如我们PC机采用的 INTEL 架构Q而另一些是采用高位先发送的方式Q在|络中交换数据时Qؓ了核对双方对于高低位的认识是否是一致的Q采用了一U很便的ҎQ就是在文本的开始时 向对方发送一个标志符——如果之后的文本是高位在位,那就发?FEFF"Q反之,则发?FFFE"。不信你可以用二q制方式打开一个UTF-X格式?文gQ看看开头两个字节是不是q两个字节?
讲到q里Q我们再Z说说一个很著名的奇怪现象:当你?windows 的记事本里新Z个文Ӟ输入"联?两个字之后,保存Q关闭,然后再次打开Q你会发现这两个字已l消׃Q代之的是几个ؕ码!呵呵Q有q就是联通之所以拼不过Ud的原因?/p>
其实q是因ؓGB2312~码与UTF8~码产生了编码冲撞的原因?nbsp;
从网上引来一D从UNICODE到UTF8的{换规则:
Unicode UTF-8
(0-127) 0000 - 007F 0xxxxxxx
(128-2047) 0080 - 07FF 110xxxxx 10xxxxxx
(2048-65535) 0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx
例如"?字的Unicode~码?C49?C49?800-FFFF之间Q所以要?字节模板Q?110xxxx 10xxxxxx 10xxxxxx。将6C49写成二进制是Q?110 1100 0100 1001Q将q个比特按三字节模板的分段Ҏ分ؓ0110 110001 001001Q依ơ代替模板中的xQ得刎ͼ1110-0110 10-110001 10-001001Q即E6 B1 89Q这是其UTF8的编码?nbsp;
而当你新Z个文本文件时Q记事本的编码默认是ANSI,如果你在ANSI的编码输入汉字,那么他实际就是GBpd的编码方式,在这U编码下Q?联?的内码是Q?nbsp;
c1 1100 0001
aa 1010 1010
cd 1100 1101
a8 1010 1000
注意C吗?W一二个字节、第三四个字节的起始部分的都?110"?10"Q正好与UTF8规则里的两字节模板是一致的Q于是再ơ打开C本时Q记?本就误认是一个UTF8~码的文Ӟ让我们把W一个字节的110和第二个字节?0LQ我们就得到?00001 101010"Q再把各位对齐,补上前导?Q就得到?0000 0000 0110 1010"Q不好意思,q是UNICODE?06AQ也是写的字?j"Q而之后的两字节用UTF8解码之后?368Q这个字W什么也不是。这?是只?联?两个字的文g没有办法在记事本里正常显C的原因?/p>
而如果你?联?之后多输入几个字Q其他的字的~码不见得又恰好?10?0开始的字节Q这样再ơ打开ӞC本就不会坚持q是一个utf8~码的文Ӟ而会用ANSI的方式解MQ这时ؕ码又不出C?br />
好了Q终于可以回{NICO的问题了Q在数据库里Q有n前缀的字串类型就是UNICODEcdQ这U类型中Q固定用两个字节来表CZ个字W,无论q个字符是汉字还是英文字母,或是别的什么?/p>
如果你要试"abc汉字"q个串的长度Q在没有n前缀的数据类型里Q这个字串是7个字W的长度Q因Z个汉字相当于两个字符。而在有n前缀的数据类型里Q同L试串长度的函数会告诉你是5个字W,因ؓ一个汉字就是一个字W?/p>