??xml version="1.0" encoding="utf-8" standalone="yes"?>
从计机对多国语a的支持角度看Q大致可以分Z个阶D:
pȝ内码 说明 pȝ
阶段一 ASCII 计算机刚开始只支持pQ其它语a不能够在计算Z存储和显C?英文 DOS
阶段?ANSI~码
Q本地化Q?Z计算机支持更多语aQ通常使用 0x80~0xFF 范围?2 个字节来表示 1 个字W。比如:汉字 '? 在中文操作系l中Q?[0xD6,0xD0] q两个字节存储?/p>
不同的国家和地区制定了不同的标准Q由此生了 GB2312, BIG5, JIS {各自的~码标准。这些?2 个字节来代表一个字W的各种汉字延~码方式Q称?ANSI ~码。在体中文系l下QANSI ~码代表 GB2312 ~码Q在日文操作pȝ下,ANSI ~码代表 JIS ~码?/p>
不同 ANSI ~码之间互不兼容Q当信息在国际间交流Ӟ无法属于两U语a的文字,存储在同一D?ANSI ~码的文本中?中文 DOSQ中?Windows 95/98Q日?Windows 95/98
阶段?UNICODE
Q国际化Q?Z使国际间信息交流更加方便Q国际组l制定了 UNICODE 字符集,为各U语a中的每一个字W设定了l一q且唯一的数字编P以满语言、跨q_q行文本转换、处理的要求?Windows NT/2000/XPQLinuxQJava
字符串在内存中的存放ҎQ?/p>
?ASCII 阶段Q单字节字符串用一个字节存放一个字W(SBCSQ。比如,"Bob123" 在内存中为:
42 6F 62 31 32 33 00
B o b 1 2 3 \0
在?ANSI ~码支持多种语言阶段Q每个字W用一个字节或多个字节来表C(MBCSQ,因此Q这U方式存攄字符也被UC多字节字W。比如,"中文123" 在中?Windows 95 内存中ؓ7个字节,每个汉字?个字节,每个英文和数字字W占1个字节:
D6 D0 CE C4 31 32 33 00
??1 2 3 \0
?UNICODE 被采用之后,计算机存攑֭W串Ӟ改ؓ存放每个字符?UNICODE 字符集中的序受目前计机一般?2 个字节(16 位)来存放一个序PDBCSQ,因此Q这U方式存攄字符也被UC宽字节字W。比如,字符?"中文123" ?Windows 2000 下,内存中实际存攄?5 个序P
2D 4E 87 65 31 00 32 00 33 00 00 00 ← ?x86 CPU 中,低字节在?
??1 2 3 \0
一共占 10 个字节?/p>
回页?br />
1.2 字符Q字节,字符?br /> 理解~码的关键,是要把字W的概念和字节的概念理解准确。这两个概念ҎhQ我们在此做一下区分:
概念描述 举例
字符 Z使用的记P抽象意义上的一个符受?'1', '?, 'a', '$', 'K?, ……
字节 计算Z存储数据的单元,一?位的二进制数Q是一个很具体的存储空间?0x01, 0x45, 0xFA, ……
ANSI
字符?在内存中Q如?#8220;字符”是以 ANSI ~码形式存在的,一个字W可能用一个字节或多个字节来表C,那么我们U这U字W串?ANSI 字符串或者多字节字符丌Ӏ?"中文123"
Q占7字节Q?
UNICODE
字符?在内存中Q如?#8220;字符”是以?UNICODE 中的序号存在的,那么我们U这U字W串?UNICODE 字符串或者宽字节字符丌Ӏ?L"中文123"
Q占10字节Q?
׃不同 ANSI ~码所规定的标准是不相同的Q因此,对于一个给定的多字节字W串Q我们必ȝ道它采用的是哪一U编码规则,才能够知道它包含了哪?#8220;字符”。而对?UNICODE 字符串来_不管在什么环境下Q它所代表?#8220;字符”内容L不变的?/p>
回页?br />
1.3 字符集与~码
各个国家和地区所制定的不?ANSI ~码标准中,都只规定了各自语a所需?#8220;字符”。比如:汉字标准QGB2312Q中没有规定韩国语字W怎样存储。这?ANSI ~码标准所规定的内容包含两层含义:
使用哪些字符。也是说哪些汉字,字母和符号会被收入标准中。所包含“字符”的集合就叫做“字符?#8221;?
规定每个“字符”分别用一个字节还是多个字节存储,用哪些字节来存储Q这个规定就叫做“~码”?
各个国家和地区在制定~码标准的时候,“字符的集?#8221;?#8220;~码”一般都是同时制定的。因此,q_我们所说的“字符?#8221;Q比如:GB2312, GBK, JIS {,除了?#8220;字符的集?#8221;q层含义外,同时也包含了“~码”的含义?/p>
“UNICODE 字符?#8221;包含了各U语a中用到的所?#8220;字符”。用来给 UNICODE 字符集编码的标准有很多种Q比如:UTF-8, UTF-7, UTF-16, UnicodeLittle, UnicodeBig {?/p>
1.4 常用的编码简?br /> 单介l一下常用的~码规则Qؓ后边的章节做一个准备。在q里Q我们根据编码规则的特点Q把所有的~码分成三类Q?/p>
分类 ~码标准 说明
单字节字W编?ISO-8859-1 最单的~码规则Q每一个字节直接作Z?UNICODE 字符。比如,[0xD6, 0xD0] q两个字节,通过 iso-8859-1 转化为字W串Ӟ直接得?[0x00D6, 0x00D0] 两个 UNICODE 字符Q即 "ÖÐ"?/p>
反之Q将 UNICODE 字符串通过 iso-8859-1 转化为字节串Ӟ只能正常转化 0~255 范围的字W?
ANSI ~码 GB2312,
BIG5,
Shift_JIS,
ISO-8859-2 …… ?UNICODE 字符串通过 ANSI ~码转化?#8220;字节?#8221;ӞҎ各自~码的规定,一?UNICODE 字符可能转化成一个字节或多个字节?/p>
反之Q将字节串{化成字符串时Q也可能多个字节转化成一个字W。比如,[0xD6, 0xD0] q两个字节,通过 GB2312 转化为字W串Ӟ得?[0x4E2D] 一个字W,?'? 字?/p>
“ANSI ~码”的特点:
1. q些“ANSI ~码标准”都只能处理各自语a范围之内?UNICODE 字符?br />
2. “UNICODE 字符”?#8220;转换出来的字?#8221;之间的关pLZؓ规定的?
UNICODE ~码 UTF-8,
UTF-16, UnicodeBig …… ?#8220;ANSI ~码”cM的,把字W串通过 UNICODE ~码转化?#8220;字节?#8221;Ӟ一?UNICODE 字符可能转化成一个字节或多个字节?/p>
?#8220;ANSI ~码”不同的是Q?br /> 1. q些“UNICODE ~码”能够处理所有的 UNICODE 字符?br /> 2. “UNICODE 字符”?#8220;转换出来的字?#8221;之间是可以通过计算得到的?
我们实际上没有必要去q每一U编码具体把某一个字W编码成了哪几个字节Q我们只需要知?#8220;~码”的概念就是把“字符”转化?#8220;字节”可以了。对?#8220;UNICODE ~码”Q由于它们是可以通过计算得到的,因此Q在Ҏ的场合,我们可以M解某一U?#8220;UNICODE ~码”是怎样的规则?/p>
2. 字符与编码在E序中的实现
2.1 E序中的字符与字?br />
?C++ ?Java 中,用来代表“字符”?#8220;字节”的数据类型,以及q行~码的方法:
cd或操?C++ Java
字符 wchar_t char
字节 char byte
ANSI 字符?char[] byte[]
UNICODE 字符?wchar_t[] String
字节?#8594;字符?mbstowcs(), MultiByteToWideChar() string = new String(bytes, "encoding")
字符?#8594;字节?wcstombs(), WideCharToMultiByte() bytes = string.getBytes("encoding")
以上需要注意几点:
Java 中的 char 代表一?#8220;UNICODE 字符Q宽字节字符Q?#8221;Q?C++ 中的 char 代表一个字节?
MultiByteToWideChar() ?WideCharToMultiByte() ?Windows API 函数?nbsp;
2.2 C++ 中相兛_现方?br /> 声明一D字W串帔RQ?/p>
// ANSI 字符Ԍ内容长度 7 字节
char sz[20] = "中文123";
// UNICODE 字符Ԍ内容长度 5 ?wchar_tQ?0 字节Q?br /> wchar_t wsz[20] = L"\x4E2D\x6587\x0031\x0032\x0033";
UNICODE 字符串的 I/O 操作Q字W与字节的{换操作:
// q行时设定当?ANSI ~码QVC 格式
setlocale(LC_ALL, ".936");
// GCC 中格?br /> setlocale(LC_ALL, "zh_CN.GBK");
// Visual C++ 中用小?%sQ按?setlocale 指定~码输出到文?br />
// GCC 中用大?%S
fwprintf(fp, L"%s\n", wsz);
// ?UNICODE 字符串按?setlocale 指定的编码{换成字节
wcstombs(sz, wsz, 20);
// 把字节串按照 setlocale 指定的编码{换成 UNICODE 字符?br />
mbstowcs(wsz, sz, 20);
?Visual C++ 中,UNICODE 字符串常量有更简单的表示Ҏ。如果源E序的编码与当前默认 ANSI ~码不符Q则需要?#pragma setlocaleQ告诉编译器源程序用的~码Q?/p>
// 如果源程序的~码与当前默?ANSI ~码不一_
// 则需要此行,~译时用来指明当前源E序使用的编?br />
#pragma setlocale(".936")
// UNICODE 字符串常量,内容长度 10 字节
wchar_t wsz[20] = L"中文123";
以上需要注?#pragma setlocale ?setlocale(LC_ALL, "") 的作用是不同的,#pragma setlocale 在编译时起作用,setlocale() 在运行时起作用?/p>
2.3 Java 中相兛_现方?br /> 字符串类 String 中的内容?UNICODE 字符Ԍ
// Java 代码Q直接写中文
String string = "中文123";//come from http://www.bt285.cn http://www.5a520.cn
// 得到长度?5Q因为是 5 个字W?br /> System.out.println(string.length());
字符?I/O 操作Q字W与字节转换操作。在 Java ?java.io.* 中,?#8220;Stream”l尾的类一般是用来操作“字节?#8221;的类Q以“Reader”Q?#8220;Writer”l尾的类一般是用来操作“字符?#8221;的类?/p>
// 字符串与字节串间怺转化
// 按照 GB2312 得到字节Q得到多字节字符Ԍ
byte [] bytes = string.getBytes("GB2312");
// 从字节按?GB2312 得到 UNICODE 字符?br /> string = new String(bytes, "GB2312");
// 要将 String 按照某种~码写入文本文gQ有两种ҎQ?/p>
// W一U办法:?Stream cd入已l按照指定编码{化好的字节串
OutputStream os = new FileOutputStream("1.txt");
os.write(bytes);
os.close();
// W二U办法:构造指定编码的 Writer 来写入字W串
Writer ow = new OutputStreamWriter(new FileOutputStream("2.txt"), "GB2312");
ow.write(string);
ow.close();
/* 最后得到的 1.txt ?2.txt 都是 7 个字?*/
如果 java 的源E序~码与当前默?ANSI ~码不符Q则在编译的时候,需要指明一下源E序的编码。比如:
E:\>javac -encoding BIG5 Hello.java
以上需要注意区分源E序的编码与 I/O 操作的编码,前者是在编译时起作用,后者是在运行时起作用?/p>
3. 几种误解Q以及ؕ码生的原因和解军_?br />
3.1 Ҏ产生的误?br />
对编码的误解
误解一 在将“字节?#8221;转化?#8220;UNICODE 字符?#8221;Ӟ比如在读取文本文件时Q或者通过|络传输文本ӞҎ?#8220;字节?#8221;单地作ؓ单字节字W串Q采用每“一个字?#8221;是“一个字W?#8221;的方法进行{化?/p>
而实际上Q在非英文的环境中,应该?#8220;字节?#8221;作ؓ ANSI 字符Ԍ采用适当的编码来得到 UNICODE 字符Ԍ有可?#8220;多个字节”才能得到“一个字W?#8221;?/p>
通常Q一直在英文环境下做开发的E序员们Q容易有q种误解?
误解??DOSQWindows 98 {非 UNICODE 环境下,字符串都是以 ANSI ~码的字节Ş式存在的。这U以字节形式存在的字W串Q必ȝ道是哪种~码才能被正地使用。这使我们Ş成了一个惯性思维Q?#8220;字符串的~码”?/p>
?UNICODE 被支持后QJava 中的 String 是以字符?#8220;序号”来存储的Q不是以“某种~码的字?#8221;来存储的Q因此已l不存在“字符串的~码”q个概念了。只有在“字符?#8221;?#8220;字节?#8221;转化Ӟ或者,一?#8220;字节?#8221;当成一?ANSI 字符串时Q才有编码的概念?/p>
不少的h都有q个误解?
W一U误解,往往是导致ؕ码生的原因。第二种误解Q往往D本来ҎU正的ؕ码问题变得更复杂?/p>
在这里,我们可以看到Q其中所讲的“误解一”Q即采用?#8220;一个字?#8221;是“一个字W?#8221;的{化方法,实际上也q同于采用 iso-8859-1 q行转化。因此,我们常常使用 bytes = string.getBytes("iso-8859-1") 来进行逆向操作Q得到原始的“字节?#8221;。然后再使用正确?ANSI ~码Q比?string = new String(bytes, "GB2312")Q来得到正确?#8220;UNICODE 字符?#8221;?/p>
3.2 ?UNICODE E序在不同语a环境间移植时的ؕ?br /> ?UNICODE E序中的字符Ԍ都是以某U?ANSI ~码形式存在的。如果程序运行时的语a环境与开发时的语a环境不同Q将会导?ANSI 字符串的昄p|?/p>
比如Q在日文环境下开发的?UNICODE 的日文程序界面,拿到中文环境下运行时Q界面上显CZؕ码。如果这个日文程序界面改为采?UNICODE 来记录字W串Q那么当在中文环境下q行Ӟ界面上将可以昄正常的日文?/p>
׃客观原因Q有时候我们必d中文操作pȝ下运行非 UNICODE 的日文YӞq时我们可以采用一些工P比如Q南极星QAppLocale {,暂时的模拟不同的语言环境?/p>
3.3 |页提交字符?br /> 当页面中的表单提交字W串Ӟ首先把字W串按照当前面的编码,转化成字节串。然后再每个字节{化成 "%XX" 的格式提交到 Web 服务器。比如,一个编码ؓ GB2312 的页面,提交 "? q个字符串时Q提交给服务器的内容?"%D6%D0"?/p>
在服务器端,Web 服务器把收到?"%D6%D0" 转化?[0xD6, 0xD0] 两个字节Q然后再Ҏ GB2312 ~码规则得到 "? 字?/p>
?Tomcat 服务器中Qrequest.getParameter() 得到qӞ常常是因为前面提到的“误解一”造成的。默认情况下Q当提交 "%D6%D0" l?Tomcat 服务器时Qrequest.getParameter() 返?[0x00D6, 0x00D0] 两个 UNICODE 字符Q而不是返回一?"? 字符。因此,我们需要?bytes = string.getBytes("iso-8859-1") 得到原始的字节串Q再?string = new String(bytes, "GB2312") 重新得到正确的字W串 "??/p>
3.4 从数据库d字符?br />
通过数据库客LQ比?ODBC ?JDBCQ从数据库服务器中读取字W串Ӟ客户端需要从服务器获知所使用?ANSI ~码。当数据库服务器发送字节流l客LӞ客户端负责将字节按照正的~码转化?UNICODE 字符丌Ӏ?/p>
如果从数据库d字符串时得到qQ而数据库中存攄数据又是正确的,那么往往q是因ؓ前面提到?#8220;误解一”造成的。解决的办法q是通过 string = new String( string.getBytes("iso-8859-1"), "GB2312") 的方法,重新得到原始的字节串Q再重新使用正确的编码{化成字符丌Ӏ?/p>
3.5 电子邮g中的字符?br /> 当一D?Text 或?HTML 通过电子邮g传送时Q发送的内容首先通过一U指定的字符~码转化?#8220;字节?#8221;Q然后再?#8220;字节?#8221;通过一U指定的传输~码QContent-Transfer-EncodingQ进行{化得到另一?#8220;字节?#8221;。比如,打开一电子邮件源代码Q可以看到类似的内容Q?/p>
Content-Type: text/plain;
charset="gb2312"
Content-Transfer-Encoding: base64
sbG+qcrQuqO17cf4yee74bGjz9W7+b3wudzA7dbQ0MQNCg0KvPKzxqO6uqO17cnnsaPW0NDEDQoNCg==
最常用?Content-Transfer-Encoding ?Base64 ?Quoted-Printable 两种。在对二q制文g或者中文文本进行{化时QBase64 得到?#8220;字节?#8221;?Quoted-Printable 更短。在对英文文本进行{化时QQuoted-Printable 得到?#8220;字节?#8221;?Base64 更短?/p>
邮g的标题,用了一U更短的格式来标?#8220;字符~码”?#8220;传输~码”。比如,标题内容?"?Q则在邮件源代码中表CZؓQ?/p>
// 正确的标题格?br /> Subject: =?GB2312?B?1tA=?=
其中Q?/p>
W一?#8220;=?”?#8220;?”中间的部分指定了字符~码Q在q个例子中指定的?GB2312?
“?”?#8220;?”中间?#8220;B”代表 Base64。如果是“Q”则代?Quoted-Printable?
最?#8220;?”?#8220;?=”之间的部分,是l过 GB2312 转化成字节串Q再l过 Base64 转化后的标题内容?
如果“传输~码”改ؓ Quoted-PrintableQ同P如果标题内容?"?Q?/p>
// 正确的标题格?br /> Subject: =?GB2312?Q?=D6=D0?=
如果阅读邮g时出Cؕ码,一般是因ؓ“字符~码”?#8220;传输~码”指定有误Q或者是没有指定。比如,有的发邮件组件在发送邮件时Q标?"?Q?/p>
// 错误的标题格?br /> Subject: =?ISO-8859-1?Q?=D6=D0?=
q样的表C,实际上是明确指明了标题ؓ [0x00D6, 0x00D0]Q即 "ÖÐ"Q而不?"??/p>
4. 几种错误理解的纠?br />
误解Q?#8220;ISO-8859-1 是国际编码?”
非也。iso-8859-1 只是单字节字W集中最单的一U,也就?#8220;字节~号”?#8220;UNICODE 字符~号”一致的那种~码规则。当我们要把一?#8220;字节?#8221;转化?#8220;字符?#8221;Q而又不知道它是哪一U?ANSI ~码Ӟ先暂时地?#8220;每一个字?#8221;作ؓ“一个字W?#8221;q行转化Q不会造成信息丢失。然后再使用 bytes = string.getBytes("iso-8859-1") 的方法可恢复到原始的字节丌Ӏ?/p>
误解Q?#8220;Java 中,怎样知道某个字符串的内码Q?#8221;
Java 中,字符串类 java.lang.String 处理的是 UNICODE 字符Ԍ不是 ANSI 字符丌Ӏ我们只需要把字符串作?#8220;抽象的符L?#8221;来看待。因此不存在字符串的内码的问题?/p>
另外一个容易在服务器端出现的多U程问题是——死锁。死锁指两个或两个以上的U程Z使用某个临界资源而无限制的等待下厅R还是以前面卫生间的例子来说明死锁,例如两个人都同时到达卫生_而且两个人都比较CDQ第一个h和第二个Q你先吧Q第二个人和W一个h_你先吧。这两个人就q样一直在互相CDQ谁也不q入Q这U现象就是死锁。这里的两个人就好比是线E,而卫生间在这里就是界资源,而由于这两个U程在一直谦让,谁也不用界资源?/p>
死锁不仅使程序无法达到预期实现的功能Q而且费pȝ的资源,所以在服务器端E序中危x较大Q在实际的服务器端程序开发中Q需要注意避免死锁?/p>
而死锁的比较麻烦,而且不一定每ơ都出现Q这需要在试服务器端E序Ӟ有够的耐心Q仔l观察程序执行时的性能,如果发现执行的性能显著降低Q则很可能是发生了死锁,然后再具体的查找死锁出现的原因,q解x锁的问题?/p>
死锁出现的最本质原因q是逻辑处理不够严}Q在考虑时不是很周全Q所以一般需要修改程序逻辑才能够很好的解决死锁?/p>
2. U程优先U?br /> 在日常生zMQ例如火车售窗口等l常可以看到“XXX优先”Q那么多U程~程中每个线E是否也可以讄优先U呢Q?/p>
在多U程~程中,支持为每个线E设|优先。优先高的U程在排队执行时会获得更多的CPU执行旉Q得到更快的响应。在实际E序中,可以Ҏ逻辑的需要,需要得到及时处理的U程讄成较高的优先U,而把Ҏ间要求不高的U程讄成比较低的优先?/p>
在ThreadcMQ总计规定了三个优先Q分别ؓQ?/p>
l MAX_PRIORITY——最高优先
l NORM_PRIORITY——普通优先Q也是默认优先
l MIN_PRIORITY——最低优先
在前面创建的U程对象中,׃没有讄U程的优先Q则U程默认的优先是NORM_PRIORITYQ在实际使用Ӟ也可以根据需要用ThreadcM的setPriorityҎ讄U程的优先Q该Ҏ的声明ؓQ?/p>
public final void setPriority(int newPriority)
假设t是一个初始化q的U程对象Q需要设|t的优先为最高,则实现的代码为:
t. setPriority(Thread. MAX_PRIORITY);
q样Q在该线E执行时获得更多的执行ZQ也是优先执行。如果由于安全等原因Q不允许讄U程的优先Q则会抛出SecurityException异常?/p>
下面使用一个简单的输出数字的线E演C线E优先的用,实现的示例代码如下:
package priority;
/**
* 试U程优先U?br />
* author by http://www.bt285.cn http://www.5a520.cn
*/
public class TestPriority {
public static void main(String[] args) {
PrintNumberThread p1 = new PrintNumberThread("高优先");
PrintNumberThread p2 = new PrintNumberThread("普通优先");
PrintNumberThread p3 = new PrintNumberThread("低优先");
p1.setPriority(Thread.MAX_PRIORITY);
p2.setPriority(Thread.NORM_PRIORITY);
p3.setPriority(Thread.MIN_PRIORITY);
p1.start();
p2.start();
p3.start();
}
}
package priority;
/**
* 输出数字的线E?/p>
*/
public class PrintNumberThread extends Thread {
String name;
public PrintNumberThread(String name){
this.name = name;
}
public void run(){
try{
for(int i = 0;i < 10;i++){
System.out.println(name + ":" + i);
}
}catch(Exception e){}
}
}
E序的一U执行结果ؓQ?/p>
高优先:0
高优先:1
高优先:2
普通优先:0
高优先:3
普通优先:1
高优先:4
普通优先:2
高优先:5
高优先:6
高优先:7
高优先:8
高优先:9
普通优先:3
普通优先:4
普通优先:5
普通优先:6
普通优先:7
普通优先:8
普通优先:9
低优先:0
低优先:1
低优先:2
低优先:3
低优先:4
低优先:5
低优先:6
低优先:7
低优先:8
低优先:9
在该CZE序QPrintNumberThreadU程实现的功能是输出数字Q每ơ数字输Z间没有设|时间gq,在测试类TestPriority中创Z个PrintNumberThreadcd的线E对象,然后分别讄U程优先U是最高、普通和最低,接着启动U程执行E序。从执行l果可以看出高优先的线E获得了更多的执行时_首先执行完成Q而低优先U的U程׃优先U较低,所以最后一个执行结束?/p>
其实Q对于线E优先的管理主要由pȝ的线E调度实玎ͼ较高优先U的U程优先执行Q所以可以通过讄U程的优先影响U程的执行?/p>
5 ȝ
关于多线E的基础知识׃l这么多Q在本章中介l了U程的概c线E的实现方式以及使用多线E时会遇到的问题以及解决办法Q而需要徏立多U程的概念,也就是ƈ发编E的概念q需要进行比较多的练习,理解多线E的概念q熟悉多U程的编E?/p>
而关于多U程~程的高U知识,如线E组{则可以在熟悉了U程的基本概念以后再q行更加深入的学习?/p>
JarResources JR=new JarResources(" http://www.bt285.cn /GifBundle.jar");
Image logo=Toolkit.getDefaultToolkit().createImage(JR.getResources("logo.gif"));
JarResources
对象Qƈ其初始化ؓ包含我们要用的资源?/span> jar 文g -- images.jar
。随后我们?/span>JarResources
?/span>getResource()
Ҏ来?/span> logo.gif 文g的原始数据提供给 awt Toolkit ?/span>createImage()
Ҏ?/span>JarReources
cȝ重要数据域用来跟t和存储指定 jar 文g的内容:public final class JarResources {
public boolean debugon=false;
private Hashtable htsizes=new Hashtable();
private Hashtable htjarcontents=new Hashtable();
private String jarfilename;
init()
Ҏ完成全部实际工作?/span>
public JarResources(String jarfilename) {
this.jarfilename=jarfilename;
init();
}
init()
Ҏ只将指定 jar 文g的整个内容加载到一?/span> hashtableQ通过资源名访问)中?/span> ZipFile
cMؓ我们提供了对 jar/zip 档案头信息的基本讉KҎ。这cM于文件系l中的目录信息。下面我们列?/span>ZipFile
中的所有条目,q用档案中每个资源的大小d htsizes hashtableQ?/span> private void init() {
try {
// extracts just sizes only.
ZipFile zf=new ZipFile(jarFileName);
Enumeration e=zf.entries();
while (e.hasMoreElements()) {
ZipEntry ze=(ZipEntry)e.nextElement();
if (debugOn) {
System.out.println(dumpZipEntry(ze));
}
htSizes.put(ze.getName(),new Integer((int)ze.getSize()));
}
zf.close();
ZipInputStream
c访问档案?/span>ZipInputStream
cd成了全部术Q允许我们单独读取档案中的每个资源。我们从档案中读取组成每个资源的_字节敎ͼq将其存储在 htjarcontents hashtable 中,您可以通过资源名访问这些数据:
// extract resources and put them into the hashtable.
FileInputStream fis=new FileInputStream(jarFileName);
BufferedInputStream bis=new BufferedInputStream(fis);
ZipInputStream zis=new ZipInputStream(bis);
ZipEntry ze=null;
while ((ze=zis.getNextEntry())!=null) {
if (ze.isDirectory()) {
continue;////啊哟!没有处理子目录中的资源啊 http://www.5a520.cn 说520|?/span>
}
if (debugOn) {
System.out.println(
"ze.getName()="+ze.getName()+","+"getSize()="+ze.getSize()
);
}
int size=(int)ze.getSize();
// -1 means unknown size.
if (size==-1) {
size=((Integer)htSizes.get(ze.getName())).intValue();
}
byte[] b=new byte[(int)size];
int rb=0;
int chunk=0;
while (((int)size - rb) > 0) {
chunk=zis.read(b,rb,(int)size - rb);
if (chunk==-1) {
break;
}
rb+=chunk;
}
// add to internal resource hashtable
htJarContents.put(ze.getName(),b);
if (debugOn) {
System.out.println(
ze.getName()+" rb="+rb+
",size="+size+
",csize="+ze.getCompressedSize()
);
}
}
} catch (NullPointerException e) {
System.out.println("done.");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
ZipEntry
cd被命名ؓ "java/util/zip/ZipEntry"Q而不?/span> "java.util.zip.ZipEntry"?/span> /**
* Dumps a zip entry into a string.
* @param ze a ZipEntry
*/
private String dumpZipEntry(ZipEntry ze) {
StringBuffer sb=new StringBuffer();
if (ze.isDirectory()) {
sb.append("d ");
} else {
sb.append("f ");
}
if (ze.getMethod()==ZipEntry.STORED) {
sb.append("stored ");
} else {
sb.append("defalted ");
}
sb.append(ze.getName());
sb.append("\t");
sb.append(""+ze.getSize());
if (ze.getMethod()==ZipEntry.DEFLATED) {
sb.append("/"+ze.getCompressedSize());
}
return (sb.toString());
}
/**
* Extracts a jar resource as a blob.
* @param name a resource name.
*/
public byte[] getResource(String name) {
return (byte[])htJarContents.get(name);
}
public static void main(String[] args) throws IOException {
if (args.length!=2) {
System.err.println(
"usage: java JarResources < jar file name> < resource name>"
);
System.exit(1);
}
JarResources jr=new JarResources(args[0]);
byte[] buff=jr.getResource(args[1]);
if (buff==null) {
System.out.println("Could not find "+args[1]+".");
} else {
System.out.println("Found "+args[1]+ " (length="+buff.length+").");
}
}
} // End of JarResources class.
public class ImageScale {
private int width;
private int height;
private int scaleWidth;
double support = (double) 3.0;
double PI = (double) 3.14159265358978;
double[] contrib;
double[] normContrib;
double[] tmpContrib;
int startContrib, stopContrib;
int nDots;
int nHalfDots;
public BufferedImage imageZoomOut(BufferedImage srcBufferImage, int w, int h) {
width = srcBufferImage.getWidth();
height = srcBufferImage.getHeight();
scaleWidth = w;
if (DetermineResultSize(w, h) == 1) {
return srcBufferImage;
}
CalContrib();
BufferedImage pbOut = HorizontalFiltering(srcBufferImage, w);
BufferedImage pbFinalOut = VerticalFiltering(pbOut, h);
return pbFinalOut;
}
/**
* 军_囑փ寸
*/
private int DetermineResultSize(int w, int h) {
double scaleH, scaleV;
scaleH = (double) w / (double) width;
scaleV = (double) h / (double) height;
// 需要判断一下scaleHQscaleVQ不做放大操?br />
if (scaleH >= 1.0 && scaleV >= 1.0) {
return 1;
}
return 0;
} // end of DetermineResultSize()
private double Lanczos(int i, int inWidth, int outWidth, double Support) {
double x;
x = (double) i * (double) outWidth / (double) inWidth;
return Math.sin(x * PI) / (x * PI) * Math.sin(x * PI / Support)
/ (x * PI / Support);
} // end of Lanczos()
//
// Assumption: same horizontal and vertical scaling factor
//
private void CalContrib() {
nHalfDots = (int) ((double) width * support / (double) scaleWidth);
nDots = nHalfDots * 2 + 1;
try {
contrib = new double[nDots];
normContrib = new double[nDots];
tmpContrib = new double[nDots];
} catch (Exception e) {
System.out.println("init contrib,normContrib,tmpContrib" + e);
}
int center = nHalfDots;
contrib[center] = 1.0;
double weight = 0.0;
int i = 0;
for (i = 1; i <= center; i++) {
contrib[center + i] = Lanczos(i, width, scaleWidth, support);
weight += contrib[center + i];
}
for (i = center - 1; i >= 0; i--) {
contrib[i] = contrib[center * 2 - i];
}
weight = weight * 2 + 1.0;
for (i = 0; i <= center; i++) {
normContrib[i] = contrib[i] / weight;
}
for (i = center + 1; i < nDots; i++) {
normContrib[i] = normContrib[center * 2 - i];
}
} // end of CalContrib()
// 处理边缘
private void CalTempContrib(int start, int stop) {
double weight = 0;
int i = 0;
for (i = start; i <= stop; i++) {
weight += contrib[i];
}
for (i = start; i <= stop; i++) {
tmpContrib[i] = contrib[i] / weight;
}
} // end of CalTempContrib()
private int GetRedValue(int rgbValue) {
int temp = rgbValue & 0x00ff0000;
return temp >> 16;
}
private int GetGreenValue(int rgbValue) {
int temp = rgbValue & 0x0000ff00;
return temp >> 8;
}
private int GetBlueValue(int rgbValue) {
return rgbValue & 0x000000ff;
}
private int ComRGB(int redValue, int greenValue, int blueValue) {
return (redValue << 16) + (greenValue << 8) + blueValue;
}
// 行水qxo?br />
private int HorizontalFilter(BufferedImage bufImg, int startX, int stopX,
int start, int stop, int y, double[] pContrib) {
double valueRed = 0.0;
double valueGreen = 0.0;
double valueBlue = 0.0;
int valueRGB = 0;
int i, j;
for (i = startX, j = start; i <= stopX; i++, j++) {
valueRGB = bufImg.getRGB(i, y);
valueRed += GetRedValue(valueRGB) * pContrib[j];
valueGreen += GetGreenValue(valueRGB) * pContrib[j];
valueBlue += GetBlueValue(valueRGB) * pContrib[j];
}
valueRGB = ComRGB(Clip((int) valueRed), Clip((int) valueGreen),
Clip((int) valueBlue));
return valueRGB;
} // end of HorizontalFilter()
// 囄水^滤L
private BufferedImage HorizontalFiltering(BufferedImage bufImage, int iOutW) {
int dwInW = bufImage.getWidth();
int dwInH = bufImage.getHeight();
int value = 0;
BufferedImage pbOut = new BufferedImage(iOutW, dwInH,
BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < iOutW; x++) {
int startX;
int start;
int X = (int) (((double) x) * ((double) dwInW) / ((double) iOutW) + 0.5);
int y = 0;
startX = X - nHalfDots;
if (startX < 0) {
startX = 0;
start = nHalfDots - X;
} else {
start = 0;
}
int stop;
int stopX = X + nHalfDots;
if (stopX > (dwInW - 1)) {
stopX = dwInW - 1;
stop = nHalfDots + (dwInW - 1 - X);
} else {
stop = nHalfDots * 2;
}
if (start > 0 || stop < nDots - 1) {
CalTempContrib(start, stop);
for (y = 0; y < dwInH; y++) {
value = HorizontalFilter(bufImage, startX, stopX, start,
stop, y, tmpContrib);
pbOut.setRGB(x, y, value);
}
} else {
for (y = 0; y < dwInH; y++) {
value = HorizontalFilter(bufImage, startX, stopX, start,
stop, y, normContrib);
pbOut.setRGB(x, y, value);
}
}
}
return pbOut;
} // end of HorizontalFiltering()
private int VerticalFilter(BufferedImage pbInImage, int startY, int stopY,
int start, int stop, int x, double[] pContrib) {
double valueRed = 0.0;
double valueGreen = 0.0;
double valueBlue = 0.0;
int valueRGB = 0;
int i, j;
for (i = startY, j = start; i <= stopY; i++, j++) {
valueRGB = pbInImage.getRGB(x, i);
valueRed += GetRedValue(valueRGB) * pContrib[j];
valueGreen += GetGreenValue(valueRGB) * pContrib[j];
valueBlue += GetBlueValue(valueRGB) * pContrib[j];
// System.out.println(valueRed+"->"+Clip((int)valueRed)+"<-");
//
// System.out.println(valueGreen+"->"+Clip((int)valueGreen)+"<-");
// System.out.println(valueBlue+"->"+Clip((int)valueBlue)+"<-"+"-->");
}
valueRGB = ComRGB(Clip((int) valueRed), Clip((int) valueGreen),
Clip((int) valueBlue));
// System.out.println(valueRGB);
return valueRGB;
} // end of VerticalFilter()
private BufferedImage VerticalFiltering(BufferedImage pbImage, int iOutH) {
int iW = pbImage.getWidth();
int iH = pbImage.getHeight();
int value = 0;
BufferedImage pbOut = new BufferedImage(iW, iOutH,
BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < iOutH; y++) {
int startY;
int start;
int Y = (int) (((double) y) * ((double) iH) / ((double) iOutH) + 0.5);
startY = Y - nHalfDots;
if (startY < 0) {
startY = 0;
start = nHalfDots - Y;
} else {
start = 0;
}
int stop;
int stopY = Y + nHalfDots;
if (stopY > (int) (iH - 1)) {
stopY = iH - 1;
stop = nHalfDots + (iH - 1 - Y);
} else {
stop = nHalfDots * 2;
}
if (start > 0 || stop < nDots - 1) {
CalTempContrib(start, stop);
for (int x = 0; x < iW; x++) {
value = VerticalFilter(pbImage, startY, stopY, start, stop,
x, tmpContrib);
pbOut.setRGB(x, y, value);
}
} else {
for (int x = 0; x < iW; x++) {
value = VerticalFilter(pbImage, startY, stopY, start, stop,
x, normContrib);
pbOut.setRGB(x, y, value);
}
}
}
return pbOut;
} // end of VerticalFiltering()
int Clip(int x) {
if (x < 0)
return 0;
if (x > 255)
return 255;
return x;
}
public static void main(String[] args) {
}
}
}
-----------------------------------------------------------------------
public BufferedImage imageZoomOut(BufferedImage srcBufferImage, int w, int h)
我将q个ҎҎ?br />
public BufferedImage imageZoomOut(BufferedImage srcBufferImage, float w, float h)
Z方便同比例羃放,w, h改ؓflaot型作为羃放比率,其他地方作相应的改动?/p>
如果是在|页上显C的话,需要徏一个ServletQ代码如下:
package servlet;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ImageScale;
public class ImageServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setHeader("Cache-Control", "no-store");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/jpeg");
// 囄攑֜当前应用的images目录??a >http://www.feng123.com 下的文g目录?br />
String path = getServletContext().getRealPath("images/2.jpg");
BufferedImage image1 = ImageIO.read(new File(path));
if(request.getParameter("x") == null) {
ImageIO.write(image1, "jpeg", response.getOutputStream());
}else {
float w = Float.parseFloat(request.getParameter("x"));
float h;
if(request.getParameter("y") == null) {
h = w;
}else{
h = Float.parseFloat(request.getParameter("y"));
}
ImageScale is = new ImageScale();
BufferedImage image2 = is.imageZoomOut(image1, w, h);
ImageIO.write(image2, "jpeg", response.getOutputStream());
}
}
}
在web.xml中增加相应的配置Q?br />
<servlet>
<servlet-name>ImageServlet</servlet-name>
<servlet-class>servlet.ImageServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ImageServlet</servlet-name>
<url-pattern>/imageServlet</url-pattern>
</servlet-mapping>
试面 http://www.feng123.com 下的Q?br />
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gbk" />
</head>
<body>
囄~放试http://www.bt285.cn <br/>
<img src="imageServlet" />
<img src="imageServlet?x=0.9&y=0.9" />
<img src="imageServlet?x=0.8&y=0.8" />
<img src="imageServlet?x=0.7&y=0.7" />
<img src="imageServlet?x=0.6&y=0.6" />
<img src="imageServlet?x=0.5&y=0.5" />
<img src="imageServlet?x=0.4&y=0.4" />
<img src="imageServlet?x=0.3&y=0.3" />
<img src="imageServlet?x=0.2&y=0.2" />
<img src="imageServlet?x=0.1&y=0.1" />
<img src="imageServlet?x=0.08" />
<img src="imageServlet?x=0.5&y=0.7" />
</body>
</html>
然后Q说一下需?
1Q?用摄像头拍照
2Q?在文本框输入文g?
3Q?按下拍照按钮Q获取摄像头内的囑փ
4Q?在拍下的照片上有一U框截取固定大小的照片?
5Q?保存为本地图像ؓjpg格式Q不得压~画?
技术关键,怿也是大家最感兴的部分也就是如何让一个摄像头工作Qƈ拍下一张照片了?
利用JMFQ代码很单:
//利用q三个类分别获取摄像头驱动,和获取摄像头内的囑փ,获取到的囑փ是一个Swing的Componentlgc?
|
接下来就是点L照,获取摄像头内的当前图像?
代码也是很简单:
|
保存囑փ的就不多说了Q以下ؓCZ代码
|
已经甌JWebCam建立Z个开源项目,攑ֈGROQ大家发挥自q惌力加入自q代码吧,比如拍摄视频Q添加图像处理功能,{等
<Host> 节点下增加一个Value节点 <Valve className="org.apache.catalina.authenticator.SingleSignOn" debug="0" requireReauthentication="false"/> </Host>
<Realm className="org.apache.catalina.realm.JDBCRealm" debug="99" driverName="your.jdbc.driver.here" connectionURL="your.jdbc.url.here" connectionName="test" connectionPassword="test" userTable="users" userNameCol="user_name" userCredCol="user_pass" userRoleTable="user_roles" roleNameCol="role_name" />
具体做法Q?在web.xml里面加上如下的配|: <security-constraint> <web-resource-collection> <web-resource-name>http://www.bt285.cn BT下蝲 </web-resource-name> <url-pattern>/*</url-pattern> </web-resource-collection> <auth-constraint> <!-- role name 指定哪个role可以讉K,可以为多个roleQ如两个|站Q?a >http://www.5a520.cn http://www.feng123.com -->
<role-name>intrauser</role-name> </auth-constraint> </security-constraint>
在web.xml里面加上如下的配|: <login-config> <auth-method>BASIC</auth-method> <realm-name>Intra Web Application</realm-name> </login-config> <security-role> <description>The role that is required to access intrasites</description> <role-name>intrauser</role-name> </security-role>
String userid = request.gerRemoteUser();
以上是在一个Tomcat Container上的SSO实现.
如果是不同的Container上的webapp要做SSOQ这U时候一U可行的Ҏ是,最前面架一个webserverQ比如apacheQ,在webserverq层承担SSO的认证Q务,后面内部可用挂多个container? 具体都用到的时候再调查?