一些有趣的搜索引擎

四月 29, 2005
Kayak.com
Dion Almaer的blog上看到的,在这个搜索引擎中能够搜索关于航空或者旅行的一些信息,有意思的是它的用户界面,它不象一般的搜索引擎,如Dion所述:

Go ahead and do a search for a flight, and you will see that instead of the usual:

“I am searching, be back in a minute”

you get:

  • I have done x out of y
  • Here they are
  • Feel free to stop me at any time if you have enough info
  • Oh, and I am done now so here is everything

The funky changing display on the left is fun too. This is a lot nicer for me the user. I get feedback at the right time (when available), and I am engaged.

Mutiply
这个搜索引擎也不象一般的搜索引擎,它不是在整个Internet上面进行搜索,而是在你的Social Network中进行搜索,在大家加入这个搜索的network后,人们可以搜索到与自己相近的人搜索的内容, it’s really very cool and interesting

Yagoohoo!gle
一个YahooGoogle的合体,^_^,不过不是meta搜索引擎,只是用户界面上面的集成

EasyRGB

搜索Color,可以帮你找出一系列相关的颜色,有特点

Koders
Searching 190,006,436 lines of code.
帮助你搜索代码^_^
Speegle
The worlds first talking search using PanaVox Speech Technology
大致看了一下,不过也没搞太懂这个到底干嘛用的,使用这个搜索引擎搜索之后,搜索引擎会将搜索结果朗读给用户,满有特点的,不过这个特点感觉不是那么实用,似乎并不能给用户带来多大的效率提升,只是用户体验会稍许有不同.
Amazon Diamond Search
Amazon用来搜索钻石的一个搜索引擎,大量使用了Ajax的技术,界面非常酷
Iokio Camera Finder
和上面的Amazon的Diamond Search有几分相像,都是类似过滤器式的搜索,用户一下就能够看明白结果,不过这个不是靠Javascript而是靠flash来完成的.这只是该公司的一个demo,他们有一个产品Iokio Feature Finder, coming soon目前,再等等看
A desktop application for creating a lightweight Flash™ file allowing users to browse and filter information in a simple and intuitive manner.
Acronyma
专门用来查询单词缩写的搜索引擎,有英语、西班牙语、法语、德语、荷兰语、意大利语、葡萄牙语这些语种的服务,基本把欧洲的大语种都包括了。可惜我只懂英语,没试过其他语种的缩写查询。
gataga
名字不知道怎么念,不过功能确满实用的.主要是针对了现在很热的tag服务,像del.icio.usfurl等等,通过该搜索引擎可以对这些服务的tag进行搜索.

iBatis多键值查询

四月 27, 2005
摘自iBATIS SQL Maps 开发指南
Clinton Begin 著
刘 涛 译
Map类型输入参数
假如没必要写一个Java Bean作为参数,而要传入的参数又不只一个时,可以使用Map类(如HashMap,TreeMap等)作为参数对象。例如:
<statement id=”insertProduct” parameterClass=”java.util.Map”>
select * from PRODUCT
where PRD_CAT_ID = #catId#
and PRD_CODE = #code#
</statement>
可以注意到mapped statement的形式完全没有区别!上面的例子中,如果把Map对象作为输入参数去调用mapped statement,Map对象必须包含键值“catId”和“code”。键值引用的对象必须是合适的类型,以上面的例子来说,必须是Integer和String。Result Map(参见以下章节)也支持使用Map类型作为结果参数。要获得更多信息,请参见“Result Map”和“使用SQL Map API编程”部分。
Map类型也可以使用别名。例如,可以用“map”来代替“java.util.Map”。这些别名参见下面的“支持Parameter Map和Result Map的数据类型”表格。

复杂类型集合的属性
Result Map还可以装入代表复杂类型对象集合(List)的属性,用以表示在数据库中相互关系为多对多或一对多的数据。拥有集合属性的类作为“一”的一方,而在集合中的对象作为“多”的一方。用来装入对象集合的mapped statement和上面例子一样。唯一的不同是,让SQL Map架构装入复杂类型集合(List)的业务对象的属性必须是java.util.List或java.util.Collection类型。例如,如果Category拥有Product对象的List,mapped-statement就像下面的例子(假设Category类有一个叫productList的属性,类型是java.util.List):
<resultMap id=”get-category-result” class=”com.ibatis.example.Category”>
<result property=”id” column=”CAT_ID”/>
<result property=”description” column=”CAT_DESCRIPTION”/>
<result property=”productList” column=”CAT_ID” select=” getProductsByCatId”/>
</resultMap>
<resultMap id=”get-product-result” class=”com.ibatis.example.Product”>
<result property=”id” column=”PRD_ID”/>
<result property=”description” column=”PRD_DESCRIPTION”/>
</resultMap>
<statement id=”getCategory” parameterClass=”int” resultMap=”get-category-result”>
select * from CATEGORY where CAT_ID = #value#
</statement>
<statement id=”getProductsByCatId” parameterClass=”int” resultMap=”get-product-result”>
select * from PRODUCT where PRD_CAT_ID = #value#
</statement>

各种键盘布局

四月 26, 2005

早就听说电脑键盘有着不同的布局,不过一直没有见识过,今天在看Matt Raible的Raible Designs时,看到他讲到了Dvorak键盘布局,于是忽然兴起,上网搜了一下相关的一些内容^_^摘自www.pconline.com.cn

键盘的历史

键盘非常悠久,早在1714年,就开始相继有英、美、法、意、瑞士等国家的人发明了各种形式的打字机,最早的键盘就是那个时候用在那些技术还不成熟的打字机上的。直到1868年,“打字机之父”――美国人克里斯托夫・拉森・肖尔斯(Christopher Latham Sholes)获打字机模型专利并取得经营权经营,又于几年后设计出现代打字机的实用形式和首次规范了键盘,即现在的“QWERTY”键盘。

为什么要将键盘规范成现在这样的“QWERTY”键盘按键布局呢?这是因为最初,打字机的键盘是按照字母顺序排列的,而打字机是全机械结构的打字工具,因此如果打字速度过快,某些键的组合很容易出现卡键问题,于是克里斯托夫・拉森・肖尔斯(Christopher Latham Sholes)发明了QWERTY键盘布局,他将最常用的几个字母安置在相反方向,最大限度放慢敲键速度以避免卡键。肖尔斯在1868年申请专利,1873年使用此布局的第一台商用打字机成功投放市场。这就是为什么有今天键盘的排列方式。

QWERTY的键盘按键布局方式非常没效率。比如:大多数打字员惯用右手,但使用QWERTY键盘,左手却负担了57%的工作。两小指及左无名指是最没力气的指头,却频频要使用它们。排在中列的字母,其使用率仅占整个打字工作的30%左右,因此,为了打一个字,时常要上上下下移动指头。

1888年全美举行打字公开比赛,法院速记员马加林按照明确的指法分工展示了他的盲打技术,错误只有万分之三,使在场人惊讶不已,据记载马加林的奖金是$500元, 从这以后很多人效仿这种盲打,在美国也开始有了专门培养打字员的学校。

由于盲打技术的出现,使得击键速度足以满足日常工作的需要,然而在60年后(1934年),华盛顿一个叫德沃拉克(Dvorak)的人为使左右手能交替击打更多的单词又发明了一种新的排列方法,这个键盘可缩短训练周期1/2时间,平均速度提高35%。DVORAK键盘布局原则是:1、尽量左右手交替击打,避免单手连击;2、越排击键平均移动距离最小;3、排在导键位置应是最常用的字母。

比DUORAK键盘更加合理、高效的是理连・莫尔特(Lillian Malt)发明的MALT键盘。它改变了原本交错的字键行列,并使拇指得到更多使用、使“后退键”(Backspace)及其他原本远离键盘中心的键更容易触到。但MALT键盘需要特别的硬件才能安装到电脑上,所以也没有得到广泛应用。

到了20世纪中期,键盘又多了一个用武之地――作为电脑的基本输入设备。另一方面,至今,“QWERTY”键盘仍然是使用的最多的键盘布局方式,这是一个非常典型的“劣势产品战胜优势产品”的例子。

摘自www.microsoft.com:

德沃夏克键盘布局

摘自www.mwbrooks.com:

Introducting to the Drorak Keyboard

小提示

亲自试用DVORAK键盘吧!
Windows中已经内置了对它的支持,打开“控制面板→键盘”,进入“输入法区域设置”选项卡,接着单击“添加”按钮,将“输入法区域设置”设置为“英语(美国)”,并在“键盘布局/输入法”栏内找到“美国英语-DVORAK”。确认后,按键位置全变了。现在你完全有资本提升自己的英文打字速度了。当然在成功前仍需花时间重新适应新的系统并进行耐心训练。

现在越来越多的本地的软件开始往web上转移了,最一开始是一些很自然能想到的东西,比如在线的所见即所得的编辑器;后来的一些似乎也可以想象,比如文件系统向web的转移(现在有很多的网上的文件存储服务,如mofile );渐渐的有一些本地的应用也开始往web上面转移了,比如翻译软件和字典软件(例如金山词霸在线,在线游戏就不算了^_^);再后来发展到有一些不那么容易想到的东西,比如收藏夹也开始往web上转移(例如现在很流行的网络书签,del.icio.us等);到现在,随着RIA的发展,web的用户界面越来越强,已经是什么本地应用都可能在web上出现了,今天甚至看到了web上的拼音输入法.再接下去会是什么呢,不久的以后是不是整个os都会搬到web上呢?那时的浏览器岂不是成了超级app-killer,所有的应用集其一身?难怪Google要拉拢Firefox了就.

很酷的Google Talk

四月 21, 2005

Google Talk

Use Google talk by entering three or four words below. The system will search for this sentence at Google, find the next word and print that. Than it will remove the first word of the search string, add the found word and repeat. The result seems to be meaningfull sometimes. Other times it is giblish. But always fun.

Google talk a Google Hack by Douwe Osinga

In the examples below, the seed text in bold, what Google returns is not. You can use Google Talk as an oracle by starting sentences and have Google Talk finish them. For example:

You want to know what a good programmer is, so you type: a good programmer is.
Google Talk answers: A good programmer is a lazy programmer
Or, you want to know how to better the world
Better the world by consolidating character in societies, families, and individuals

Also, you can find out who stars in a movie by typing the name of the movie followed by starring:
The Godfather starring Marlon Brando Al Pacino James Caan, Robert Duvall, Arthur Hill, Bo Hopkins, Mako, Gig Young. Dir. Sam Peckinpah. Folded Price
It starts to trash after while

Or have Google Talk write your contracts:
not plagiarized from any other source. for any reason. whatsoever. including but not LIMITED to the following: A.

Use Google Talk to find out where the bad guys hide:
Saddam Hussein hides in the cellars under the main house and the Carriage house
Osama bin Laden hides in the latticed caves of Afghanistan, he has been able to help them in their efforts to implement the principles of the Arcane School

Ant全攻略

转自:BEA论坛 powerise

1.Ant是什么?
Ant是一种基于Java和XML的build工具。

2 下载、安装Ant
安装Ant
下载.zip文件,解压缩到c:\ant1.3(后面引用为%ANT_HOME%)

2.1 在你运行Ant之前需要做一些配置工作。
・ 将bin目录加入PATH环境变量。
・ 设定ANT_HOME环境变量,指向你安装Ant的目录。在一些OS上,Ant的脚本可以猜测ANT_HOME(Unix和Windos NT/2000)-但最好不要依赖这一特性。
・ 可选地,设定JAVA_HOME环境变量(参考下面的高级小节),该变量应该指向你安装JDK的目录。
注意:不要将Ant的ant.jar文件放到JDK/JRE的lib/ext目录下。Ant是个应用程序,而lib/ext目录是为JDK扩展使用的(如JCE,JSSE扩展)。而且通过扩展装入的类会有安全方面的限制。
2.2 运行Ant

运行Ant非常简单,当你正确地安装Ant后,只要输入ant就可以了。

n 没有指定任何参数时,Ant会在当前目录下查询build.xml文件。如果找到了就用该文件作为buildfile。如果你用 -find 选项。Ant就会在上级目录中寻找buildfile,直至到达文件系统的根。要想让Ant使用其他的buildfile,可以用参数 -buildfile file,这里file指定了你想使用的buildfile。

n 可以指定执行一个或多个target。当省略target时,Ant使用标签<project>的default属性所指定的target。

命令行选项总结:
ant [options] [target [target2 [target3] …]]
Options:
-help print this message
-projecthelp print project help information
-version print the version information and exit
-quiet be extra quiet
-verbose be extra verbose
-debug print debugging information
-emacs produce logging information without adornments
-logfile file use given file for log output
-logger classname the class that is to perform logging
-listener classname add an instance of class as a project listener
-buildfile file use specified buildfile
-find file search for buildfile towards the root of the filesystem and use the first one found
-Dproperty=value set property to value
例子
ant
使用当前目录下的build.xml运行Ant,执行缺省的target。
ant -buildfile test.xml
使用当前目录下的test.xml运行Ant,执行缺省的target。
ant -buildfile test.xml dist
使用当前目录下的test.xml运行Ant,执行一个叫做dist的target。
ant -buildfile test.xml -Dbuild=build/classes dist
使用当前目录下的test.xml运行Ant,执行一个叫做dist的target,并设定build属性的值为build/classes。

3 编写build.xml

Ant的buildfile是用XML写的。每个buildfile含有一个project。

buildfile中每个task元素可以有一个id属性,可以用这个id值引用指定的任务。这个值必须是唯一的。(详情请参考下面的Task小节)

3.1 Projects

project有下面的属性:
Attribute Description Required
name 项目名称. No
default 当没有指定target时使用的缺省target Yes
basedir 用于计算所有其他路径的基路径。该属性可以被basedir property覆盖。当覆盖时,该属性被忽略。如果属性和basedir property都没有设定,就使用buildfile文件的父目录。 No
项目的描述以一个顶级的<description>元素的形式出现(参看description小节)。

一个项目可以定义一个或多个target。一个target是一系列你想要执行的。执行Ant时,你可以选择执行那个target。当没有给定target时,使用project的default属性所确定的target。

3.2 Targets

一个target可以依赖于其他的target。例如,你可能会有一个target用于编译程序,一个target用于生成可执行文件。你在生成可执行文件之前必须先编译通过,所以生成可执行文件的target依赖于编译target。Ant会处理这种依赖关系。

然而,应当注意到,Ant的depends属性只指定了target应该被执行的顺序-如果被依赖的target无法运行,这种depends对于指定了依赖关系的target就没有影响。

Ant会依照depends属性中target出现的顺序(从左到右)依次执行每个target。然而,要记住的是只要某个target依赖于一个target,后者就会被先执行。
<target name=”A”/>
<target name=”B” depends=”A”/>
<target name=”C” depends=”B”/>
<target name=”D” depends=”C,B,A”/>
假定我们要执行target D。从它的依赖属性来看,你可能认为先执行C,然后B,最后A被执行。错了,C依赖于B,B依赖于A,所以先执行A,然后B,然后C,最后D被执行。

一个target只能被执行一次,即时有多个target依赖于它(看上面的例子)。

如果(或如果不)某些属性被设定,才执行某个target。这样,允许根据系统的状态(java version, OS, 命令行属性定义等等)来更好地控制build的过程。要想让一个target这样做,你就应该在target元素中,加入if(或unless)属性,带上target因该有所判断的属性。例如:
<target name=”build-module-A” if=”module-A-present”/>
<target name=”build-own-fake-module-A” unless=”module-A-present”/>
如果没有if或unless属性,target总会被执行。

可选的description属性可用来提供关于target的一行描述,这些描述可由-projecthelp命令行选项输出。

将你的tstamp task在一个所谓的初始化target是很好的做法,其他的target依赖这个初始化target。要确保初始化target是出现在其他target依赖表中的第一个target。在本手册中大多数的初始化target的名字是”init”。

target有下面的属性:
Attribute Description Required
name target的名字 Yes
depends 用逗号分隔的target的名字列表,也就是依赖表。 No
if 执行target所需要设定的属性名。 No
unless 执行target需要清除设定的属性名。 No
description 关于target功能的简短描述。 No

3.3 Tasks

一个task是一段可执行的代码。

一个task可以有多个属性(如果你愿意的话,可以将其称之为变量)。属性只可能包含对property的引用。这些引用会在task执行前被解析。

下面是Task的一般构造形式:
<name attribute1=”value1″ attribute2=”value2″ … />
这里name是task的名字,attributeN是属性名,valueN是属性值。

有一套内置的(built-in)task,以及一些可选task,但你也可以编写自己的task。

所有的task都有一个task名字属性。Ant用属性值来产生日志信息。

可以给task赋一个id属性:
<taskname id=”taskID” … />
这里taskname是task的名字,而taskID是这个task的唯一标识符。通过这个标识符,你可以在脚本中引用相应的task。例如,在脚本中你可以这样:
<script … >
task1.setFoo(”bar”);
</script>
设定某个task实例的foo属性。在另一个task中(用java编写),你可以利用下面的语句存取相应的实例。
project.getReference(”task1″).
注意1:如果task1还没有运行,就不会被生效(例如:不设定属性),如果你在随后配置它,你所作的一切都会被覆盖。

注意2:未来的Ant版本可能不会兼容这里所提的属性,因为很有可能根本没有task实例,只有proxies。

3.4 Properties

一个project可以有很多的properties。可以在buildfile中用property task来设定,或在Ant之外设定。一个property有一个名字和一个值。property可用于task的属性值。这是通过将属性名放在”${”和”}”之间并放在属性值的位置来实现的。例如如果有一个property builddir的值是”build”,这个property就可用于属性值:${builddir}/classes。这个值就可被解析为build/classes。

内置属性

如果你使用了<property> task 定义了所有的系统属性,Ant允许你使用这些属性。例如,${os.name}对应操作系统的名字。

要想得到系统属性的列表可参考the Javadoc of System.getProperties。

除了Java的系统属性,Ant还定义了一些自己的内置属性:
basedir project基目录的绝对路径 (与<project>的basedir属性一样)。
ant.file buildfile的绝对路径。
ant.version Ant的版本。
ant.project.name 当前执行的project的名字;由<project>的name属性设定.
ant.java.version Ant检测到的JVM的版本; 目前的值有”1.1″, “1.2″, “1.3″ and “1.4″.

例子
<project name=”MyProject” default=”dist” basedir=”.”>

<!– set global properties for this build –>
<property name=”src” value=”http://blogger.org.cn/blog/.”/>
<property name=”build” value=”build”/>
<property name=”dist” value=”dist”/>

<target name=”init”>
<!– Create the time stamp –>
<tstamp/>
<!– Create the build directory structure used by compile –>
<mkdir dir=”${build}”/>
</target>

<target name=”compile” depends=”init”>
<!– Compile the java code from ${src} into ${build} –>
<javac srcdir=”http://blogger.org.cn/blog/${src}” destdir=”http://blogger.org.cn/blog/${build}”/>
</target>

<target name=”dist” depends=”compile”>
<!– Create the distribution directory –>
<mkdir dir=”${dist}/lib”/>
<!– Put everything in ${build} into the MyProject-${DSTAMP}.jar file –>
<jar jarfile=”${dist}/lib/MyProject-${DSTAMP}.jar” basedir=”${build}”/>
</target>

<target name=”clean”>
<!– Delete the ${build} and ${dist} directory trees –>
<delete dir=”${build}”/>
<delete dir=”${dist}”/>
</target>

</project>

3.5 Path-like Structures

你可以用”:”和”;”作为分隔符,指定类似PATH和CLASSPATH的引用。Ant会把分隔符转换为当前系统所用的分隔符。

当需要指定类似路径的值时,可以使用嵌套元素。一般的形式是
<classpath>
<pathelement path=”${classpath}”/>
<pathelement location=”lib/helper.jar”/>
</classpath>
location属性指定了相对于project基目录的一个文件和目录,而path属性接受逗号或分号分隔的一个位置列表。path属性一般用作预定义的路径--其他情况下,应该用多个location属性。

为简洁起见,classpath标签支持自己的path和location属性。所以:
<classpath>
<pathelement path=”${classpath}”/>
</classpath>
可以被简写作:
<classpath path=”${classpath}”/>
也可通过<fileset>元素指定路径。构成一个fileset的多个文件加入path-like structure的顺序是未定的。
<classpath>
<pathelement path=”${classpath}”/>
<fileset dir=”lib”>
<include name=”**/*.jar”/>
</fileset>
<pathelement location=”classes”/>
</classpath>
上面的例子构造了一个路径值包括:${classpath}的路径,跟着lib目录下的所有jar文件,接着是classes目录。

如果你想在多个task中使用相同的path-like structure,你可以用<path>元素定义他们(与target同级),然后通过id属性引用--参考Referencs例子。

path-like structure可能包括对另一个path-like structurede的引用(通过嵌套<path>元素):
<path id=”base.path”>
<pathelement path=”${classpath}”/>
<fileset dir=”lib”>
<include name=”**/*.jar”/>
</fileset>
<pathelement location=”classes”/>
</path>
<path id=”tests.path”>
<path refid=”base.path”/>
<pathelement location=”testclasses”/>
</path>
前面所提的关于<classpath>的简洁写法对于<path>也是有效的,如:
<path id=”tests.path”>
<path refid=”base.path”/>
<pathelement location=”testclasses”/>
</path>
可写成:
<path id=”base.path” path=”${classpath}”/>
命令行变量

有些task可接受参数,并将其传递给另一个进程。为了能在变量中包含空格字符,可使用嵌套的arg元素。
Attribute Description Required
value 一个命令行变量;可包含空格字符。 只能用一个
line 空格分隔的命令行变量列表。
file 作为命令行变量的文件名;会被文件的绝对名替代。
path 一个作为单个命令行变量的path-like的字符串;或作为分隔符,Ant会将其转变为特定平台的分隔符。

例子
<arg value=”-l -a”/>
是一个含有空格的单个的命令行变量。
<arg line=”-l -a”/>
是两个空格分隔的命令行变量。
<arg path=”/dir;/dir2:\dir3″/>
是一个命令行变量,其值在DOS系统上为\dir;\dir2;\dir3;在Unix系统上为/dir:/dir2:/dir3 。

3.6 References

buildfile元素的id属性可用来引用这些元素。如果你需要一遍遍的复制相同的XML代码块,这一属性就很有用--如多次使用<classpath>结构。

下面的例子:
<project … >
<target … >
<rmic …>
<classpath>
<pathelement location=”lib/”/>
<pathelement path=”${java.class.path}/”/>
<pathelement path=”${additional.path}”/>
</classpath>
</rmic>
</target>
<target … >
<javac …>
<classpath>
<pathelement location=”lib/”/>
<pathelement path=”${java.class.path}/”/>
<pathelement path=”${additional.path}”/>
</classpath>
</javac>
</target>
</project>
可以写成如下形式:
<project … >
<path id=”project.class.path”>
<pathelement location=”lib/”/>
<pathelement path=”${java.class.path}/”/>
<pathelement path=”${additional.path}”/>
</path>
<target … >
<rmic …>
<classpath refid=”project.class.path”/>
</rmic>
</target>
<target … >
<javac …>
<classpath refid=”project.class.path”/>
</javac>
</target>
</project>
所有使用PatternSets, FileSets 或 path-like structures嵌套元素的task也接受这种类型的引用。
================================================================
Ant全攻略(续)---Ant中的内置任务

4.1 File(Directory)类
4.1.1 Mkdir
n 创建一个目录,如果他的父目录不存在,也会被同时创建。
n 例子:
<mkdir dir=”build/classes”/>
n 说明: 如果build不存在,也会被同时创建
4.1.2 Copy
n 拷贝一个(组)文件、目录
n 例子:
1. 拷贝单个的文件:
<copy file=”myfile.txt” tofile=”mycopy.txt”/>
2. 拷贝单个的文件到指定目录下
<copy file=”myfile.txt” todir=”../some/other/dir”/>
3. 拷贝一个目录到另外一个目录下
<copy todir=”../new/dir”>
<fileset dir=”src_dir”/>
</copy>
4. 拷贝一批文件到指定目录下
<copy todir=”http://blogger.org.cn/blog/../dest/dir”>
<fileset dir=”src_dir”>
<exclude name=”http://blogger.org.cn/blog/**/*.java”/>
</fileset>
</copy>

<copy todir=”../dest/dir”>
<fileset dir=”src_dir” excludes=”http://blogger.org.cn/blog/**/*.java”/>
</copy>
5. 拷贝一批文件到指定目录下,将文件名后增加。Bak后缀
<copy todir=”../backup/dir”>
<fileset dir=”src_dir”/>
<mapper type=”http://blogger.org.cn/blog/glob” from=”*” to=”*.bak”/>
</copy>
6. 拷贝一组文件到指定目录下,替换其中的@标签@内容
<copy todir=”../backup/dir”>
<fileset dir=”src_dir”/>
<filterset>
<filter token=”http://blogger.org.cn/blog/TITLE” value=”Foo Bar”/>
</filterset>
</copy>
4.1.3 Delete
n 删除一个(组)文件或者目录
n 例子
1. 删除一个文件
<delete file=”/lib/ant.jar”/>
2. 删除指定目录及其子目录
<delete dir=”lib”/>
3. 删除指定的一组文件
<delete>
<fileset dir=”.” includes=”**/*.bak”/>
</delete>
4. 删除指定目录及其子目录,包括他自己
<delete includeEmptyDirs=”true”>
<fileset dir=”build”/>
</delete>
4.1.4 Move
n 移动或重命名一个(组)文件、目录
n 例子:
1. 移动或重命名一个文件
<move file=”file.orig” tofile=”file.moved”/>
2. 移动或重命名一个文件到另一个文件夹下面
<move file=”file.orig” todir=”dir/to/move/to”/>
3. 将一个目录移到另外一个目录下
<move todir=”new/dir/to/move/to”>
<fileset dir=”src/dir”/>
</move>
4. 将一组文件移动到另外的目录下
<move todir=”http://blogger.org.cn/blog/some/new/dir”>
<fileset dir=”my/src/dir”>
<include name=”http://blogger.org.cn/blog/**/*.jar”/>
<exclude name=”**/ant.jar”/>
</fileset>
</move>
5. 移动文件过程中增加。Bak后缀
<move todir=”my/src/dir”>
<fileset dir=”http://blogger.org.cn/blog/my/src/dir”>
<exclude name=”http://blogger.org.cn/blog/**/*.bak”/>
</fileset>
<mapper type=”glob” from=”*” to=”*.bak”/>
</move>

================================================================
Ant全攻略 — Java相关任务
4.2.1 Javac
n 编译java原代码
n 例子
1. <javac srcdir=”http://blogger.org.cn/blog/${src}”
destdir=”http://blogger.org.cn/blog/${build}”
classpath=”xyz.jar”
debug=”on”
/>
编译${src}目录及其子目录下的所有。Java文件,。Class文件将放在${build}指定的目录下,classpath表示需要用到的类文件或者目录,debug设置为on表示输出debug信息
2. <javac srcdir=”http://blogger.org.cn/blog/${src}:${src2}”
destdir=”http://blogger.org.cn/blog/${build}”
includes=”mypackage/p1/**,mypackage/p2/**”
excludes=”mypackage/p1/testpackage/**”
classpath=”xyz.jar”
debug=”on”
/>
编译${src}和${src2}目录及其子目录下的所有。Java文件,但是package/p1/**,mypackage/p2/**将被编译,而mypackage/p1/testpackage/**将不会被编译。Class文件将放在${build}指定的目录下,classpath表示需要用到的类文件或者目录,debug设置为on表示输出debug信息
3. <property name=”http://blogger.org.cn/blog/classpath” value=”.;./xml-apis.jar;../lib/xbean.jar;./easypo.jar”/>

<javac srcdir=”http://blogger.org.cn/blog/${src}”
destdir=”http://blogger.org.cn/blog/${src}”
classpath=”http://blogger.org.cn/blog/${classpath}”
debug=”on”
/>
路径是在property中定义的
4.2.2 java
n 执行指定的java类
n 例子:
1. <java classname=”test.Main”>
<classpath>
<pathelement location=”dist/test.jar”/>
<pathelement path=”${java.class.path}”/>
</classpath>
</java>
classname中指定要执行的类,classpath设定要使用的环境变量
2. <path id=”project.class.path”>
<pathelement location=”lib/”/>
<pathelement path=”${java.class.path}/”/>
<pathelement path=”${additional.path}”/>
</path>

<target … >
<rmic …>
<classpath refid=”project.class.path”/>
</rmic>
</target>

================================================================

Ant全攻略 — 通过JDBC执行SQL语句

4.5 执行SQL语句

n 通过jdbc执行SQL语句
n 例子:
1. <sql
driver=”org.gjt.mm.mysql.Driver”
url=”jdbc:mysql://localhost:3306/mydb”
userid=”root”
password=”root”
xsrc=”http://blogger.org.cn/blog/data.sql” mce_src=”http://blogger.org.cn/blog/data.sql”
/>
2. <sql
driver=”org.database.jdbcDriver”
url=”jdbc:database-url”
userid=”sa”
password=”pass”
xsrc=”http://blogger.org.cn/blog/data.sql” mce_src=”http://blogger.org.cn/blog/data.sql”
rdbms=”oracle”
version=”8.1.”
>
</sql>
只有在oracle、版本是8.1的时候才执行

================================================================
Ant 全攻略之 --- 发送邮件

4.6 发送邮件
n 使用SMTP服务器发送邮件
n 例子:
<mail mailhost=”smtp.myisp.com” mailport=”1025″ subject=”Test build”>
<from address=”me@myisp.com”/>
<to address=”http://blogger.org.cn/blog/all@xyz.com”/>
<message>The ${buildname} nightly build has completed</message>
<fileset dir=”http://blogger.org.cn/blog/dist”>
<includes name=”**/*.zip”/>
</fileset>
</mail>
l mailhost: SMTP服务器地址
l mailport: 服务器端口
l subject: 主题
l from: 发送人地址
l to: 接受人地址
l message: 发送的消息
l fileset: 设置附件

Java界技术名人堂

四月 18, 2005

Java界技术名人堂

上次在某个blog上面看到过一个关于Java人仕的综合介绍,人列了不少,不过讲的比较没有规律并且不是很全.今天在赛迪网上看到了这些资料,但是阅读起来很不方便,这里为其修改了其链接上的错误并将原来分散的资源做了一个综合.想知道更多的人还可以看看TheServerSide上面的这篇文章: Who’s Who in the Enterprise Java World? Make your opinion known! 里面断断续续的也讲了不少人^_^

A



Adrian Colyer

IBM的AspectJ DeveloperJava研究项目负责人,同时也是Eclipse上AspectJ项目的领导者。AspectJ项目起源于帕洛阿尔托(Palo Alto)研究中心(缩写为PARC)。该中心由Xerox集团资助,Gregor Kiczales领导,从1997年开始致力于AspectJ的开发,1998年第一次发布给外部用户,2001年发布1.0 release。为了推动AspectJ技术和社团的发展,PARC在2003年3月正式将AspectJ项目移交给了Eclipse组织,因为AspectJ的发展和受关注程度大大超出了PARC的预期,他们已经无力继续维持它的发展。

AspectJ是用于实现面向方面编程(AOP)的Java语言扩展。通过分离各种正交问题,AspectJ使得开发者能够更轻松地解决大型软件系统中常见的一些棘手问题,如日志记录、错误处理之类。

AspectJ项目经过近十年的发展,对于AOP的具体实现已经相当成熟,但其仍存在诸如过于复杂、破坏封装、需要专门的Java编译器等缺点。在接收了AspectJ项目之后,Eclipse项目组已经把AspectJ集成在Eclipse Java开发环境中。通过这样的集成,Eclipse IDE将可以提供对AOP的支持,并弥补AspectJ本身的一些不足之处。


B



Ben Galbraith

AOP活跃人士,其在TSSJS2005(全称:The ServerSide Java Symposium)上关于“AJax Toy”的演讲被与会者认为颇有新意。AJAX是Asynchronous JavaScript + XML的缩写,而且AJax可以很好的和JSF的Component结合起来,开发者不需要成为AJax方面的专家。


Benjamin Renaud

BEA的副CTO。BEA是企业级平台中间件的领导厂商,其2002财年收入达到9.34亿美元,在全球拥有超过15,000家企业用户。1995年,BEA收购Tuexdo联机事物处理监视器[Tuxedo online transaction processing(OLTP) monitor],并由此而进入平台中间件市场。1998年又收购了WebLogic,而WebLogic技术随后在1999年成为Java应用服务器领域中的领导者。


Bill Burke

JBoss组织首席架构师,EJB 3.0专家组里的JBoss代表。JBoss是一个用纯Java编写、开放源代码、遵循J2EE规范的应用服务器软件,它遵循LGPL开放源码协议。JBoss起初只是一个EJB容器,后来逐步发展成为一个具有复杂功能的应用服务器。现在,最高的版本是4.0。它从创建到现在,经历了4年的发展历程。JBoss组织是一家位于美国亚特兰大的商业服务组织。他们为JBoss应用服务器提供技术支持和顾问咨询。


Bob McWhirter

Groovy和Drools的开发者。Groovy是一种敏捷开发语言,完全以Java编程API为基础,于2004年3月底获得批准。Groovy还是与JRE兼容的一种脚本语言,使用了Java开发人员最熟悉的功能和库(将它们放到了一个敏捷开发框架中)。Groovy具有使开发人员不用编译、允许动态类型、使合成结构容易、脚本可在普通Java应用程序中使用、提供shell解析器等特性,这使其成为一种特别容易学习和使用的语言,不管是有经验的Java开发人员还是刚接触Java平台的人,都可以快速掌握。有些人说它可能会永久性地改变开发人员看待和使用Java平台的方式。

Drools是Bob McWhirter开发的开源项目,是Charles Forgy Rete算法的一个增强的Java语言实现,放在The Codehaus上。Rete算法是Charles Forgy在1979年发明的,是目前用于生产系统的效率最高的算法(除了私有的Rete II)。Rete是唯一的、效率与执行规则数目无关的决策支持算法。Rete应用于生产系统已经有很多年了,但在Java开源软件中并没有得到广泛应用。

除了应用了Rete核心算法、开源软件和100%的Java实现外,Drools还提供了很多有用的特性。其中包括实现了JSR94 API和创新的规则语义系统,这个语义系统可用来编写描述规则的语言。目前,Drools提供了三种语义模块,即Python模块、Java模块和Groovy模块。


C



Cedric Beust

EJB 3专家组的成员,也是其他一些流行的开源项目(例如EJBGen和Doclipse)的创造者。目前是BEA的Weblogic架构师。EJBGen是一种EJB 2.0原始码生成器,它能够从一个EJB bean类生成本地界面/远端界面、本地主界面/远端主界面、主键类和部署描述符。

Doclipse是一个Eclipse下的JavaDoc插件。

Java中的包(Package)其实指的就是目录,它是为了更好地管理Java类(Class)和接口(Interface)。Java语言的包可以被另一个Java开发包所使用。

EJB是SUN公司倡导的基于JAVA的组件构架,是J2EE中的主要技术之一。EJB定义了一个集成的编程模型和标准的API接口,是实现服务器端应用服务的组件。



Cliff Schmidt

Cliff Schmidt,标准和开源策略产品经理,也是Apache蜂巢项目负责人。蜂巢计划(Project Beehive)是一个基于 WebLogic Workshop应用框架的用于 J2EE&SOA 应用的开源项目。该框架本身是独立的,但要依靠WebLogic来运行。 在2004年5月,BEA宣布该框架以后的所有开发都是开放源码的,这就是Apache蜂巢项目,名为Beehive。


Craig McClanahan

Craig McClanahan目前是SUN公司的高级工程师,主要从事J2EE的WEB层的工作。主要参加的开放源码有:

1.Catalina Servlet Container:主要的开发人员,该Servlet Container是Apache软件基金的Jarkarta 中的TOMCAT 4.x和5.x版中的核心部分。

2.Struts: 发起人和主要的开发人员,2000年该项目转为Apache软件基金的Jarkarta项目,该框架目前成为采用Java Servlet 和JSP技术构件Web应用的最流行的框架。

3.Digester:发起人和主要的开发人员,本来该项目是为Struts中处理配置文件的一些功能类,后来觉得不错,就转成Apache软件基金的Jarkarta项目的Common中的一个组件项目。

4.JavaServer Faces(JSR-127), 和SUN公司的Ed Burns一起负责该标准。

著作:《Struts in action》


D



David Nuescheler

Day Software的CTO,也是Java Content Repository(Java内容录仓库)JCR 170专家组负责人。Java Content Repository是一个寻址内容仓库的标准化API建议。2002年2月,该建议提交到JCR(Java Community Process),JCR专家组于2003年下半年完成最终草案。


Dion Almaer

TSS主编、中间件公司首席架构师、JDO专家组成员。Middleware Company (www.middleware-company.com)即中间件公司是领先的EJB/J2EE和B2B技术培训机构之一。Middleware Company还构建和维护一流的在线J2EE社区TheServerSide.com。


Doug Cutting

TSS的CEO、MiddleWare公司CEO、《Mastering EJB》作者。他是一位资深全文索引/检索专家,曾经是V-Twin搜索引擎(Apple的Copland操作系统的成就之一)的主要开发者,后在Excite担任高级系统架构设计师,目前从事于一些INTERNET底层架构的研究。他贡献出的Lucene的目标是为各种中小型应用程序加入全文检索功能。Lucene不是一个完整的全文索引应用,而是是一个用Java写的全文索引引擎工具包,它可以方便的嵌入到各种应用中实现针对应用的全文索引/检索功能。早先发布在作者自己的www.lucene.com,后来发布在SourceForge,2001年年底成为APACHE基金会jakarta的一个子项目:http://jakarta.apache.org/lucene/

E



Erich Gamma

经典书籍《Design Patterns(设计模式)》(Addison-Wesley,1995)的四位作者之一,Eclipse的总设计师,并且是EclipseJava开发工具(JDT)项目的领导人。


Edward Burns

JSF 1.2规格主导者。SPEC是System PerformanceEvaluation Cooperative的缩写,是几十家世界知名计算机大厂商所支持的非盈利的合作组织,旨在开发共同认可的标准基准程序。

SPEC基准程序是由SPEC开发的一组用于计算机性能综合评价的程序。以对VAX11/780机的测试结果作为基数,其他计算机的测试结果以相对于这个基数的比率来表示。SPEC基准程序能较全面地反映机器性能,有一定的参考价值。

SPEC版本1.0是1989年10月宣布的,是一套复杂的基准程序集,主要用于测试与工程和科学应用有关的数值密集型的整数和浮点数方面的计算。源程序超过15万行,包含10个测试程序,使用的数据量比较大,分别测试应用的各个方面。

SPEC基准程序测试结果一般以SPECmark(SPEC分数)、SPECint(SPEC整数)和SPECfp(SPEC浮点数)来表示。其中SPEC分数是10个程序的几何平均值,SPEC整数是4个整数程序的几何平均值,SPEC浮点数是6个浮点程序的集合平均值。

1992年在原来SPECint89和SPECfp89的基础上增加了两个整数测试程序和8个浮点数测试程序,因此SPECint92由6个程序组成,SPECfp92由14个程序组成。这20个基准程序是基于不同的应用写成的,主要测量32位cpu、主存储器、编译器和操作系统的性能。

参加这个组织的主要成员有:IBM,AT&T,BULL,Compag,CDC,DG,DEC,Fujitsu,HP,Intel,MIPS,Motorola,SGI,SUN和Unisys等。1995年,这些厂商又共同推出了SPECint95和SPECfp95作为最新的测试标准程序。


F



Floyd Marinescu

《EJB Design Patterns》作者。他架构、建置并执行了TheServerSide.com(知名J2EE社区)。他写了无以计数的文章并且经常在Java研讨会上发表演说。

G



Gavin King

Hibernate的作者,EJB3.0专家委员会成员,JBoss核心成员之一,也是《Hibernate in Action》一书的作者。Gavin King 1974年出生于澳大利亚,现在居住在澳大利亚默尔本市。Hibernate 是Java平台上的一种流行的、容易使用的开放源代码对象关系(OR)映射框架。Hibernate诞生在2001年11月,在短短的两年多时间就发展成为Java世界主流的持久层框架软件,令人侧目。Hibernate是一个雄心勃勃的项目,它的目标是成为Java中管理持续性数据问题的一种完整的解决方案。它协调应用与关系数据库的交互,让开发者解放出来专注于手边的业务问题。Hibernate是一种非强迫的解决方案。


Gregor Hohpe

《Enterprise Integration Patterns》作者,目前在ThoughtWorks工作。


Gregor Kiczales

人称AOP之父,是其领导了开发AOP和AspectJ的PARC团队。他是知名的AOP传教士,并且致力于建立同时给实践者和研究者服务的社区。他在开发高级编程技术并把这些技术传授给开发者方面有二十年的经验,是ANSI CLOS设计团队的成员,同时还是CLOS参考实现的作者,以及《The Art of Metaobject Protocol》(MIT出版社,1991)的作者之一。他现在是British Columbia大学软件设计方面的Sierra System教授。


Graham Hamilton

Sun副总裁,J2SE1.3、1.4、5.0项目领导人。

H



Hani Suleiman

OSWorkflow开发者,BileBlog的作者。osworkflow是一个轻量级的又极为灵活的工作流引擎,较容易和其它架构做整合。


Howard Lewis Ship

HLS的Blog:http://howardlewisship.com/blog/Tapestry和Hivemind的开发者,《Tapestry in Action》作者。

Tapestry是类似WebForms机制的Java Web Framework,Hivemind是一个微内核的IoC容器,Tapestry和Hivemind都是Apache Foundation Software旗下的软件。


J



James Strachan

Geronimo的发起者之一,Jakarta项目管理委员会成员,N多JSR expert group的成员。Geronimo是Apache软件基金会为了创造一个兼容J2EE的容器,而整理出来的一个新成果。

Jakarta是一个Sun公司支持的开源项目。它的最终目标是创造一个质量达到了那些商业解决方案要求的免费J2EE服务器端解决方案。Tomcat应用程序是整个项目的主要部分,并且在很多人看来,它几乎就等同于整个的Jakarta项目。



Jason Careria

Webwork2,Xwork核心的开发者。WebWork2.x前身是Rickard Oberg开发的WebWork,但现在WebWork已经被拆分成了XWork1和WebWork2两个项目。


Jason Hunter

Apache基金会管理员,《Java Servlet Programming》作者,Xquery,Jdom等的开发者。


John Crupi

Sun Java Center系统架构师,目前专著于SOA。


Jonathan Bruce

JDBC规格主导人。


Joshua Bloch

《Effective Java》作者,前java平台核心开发者,目前在google。


Jon Tirsen

Nanning的首席开发者,PicoContainer和NanoContainer活跃开发者,目前在ThoughtWorks工作,Damage Control的项目领导者之一。


Juergen Hoeler

Juergen Hoeler是SpringFramework的共同作者之一,与Rod Johnson共同发起和创造了SpringFramework。SpringFramework中Hibernate相关的API是由Juergen Hoeler完成的。对于喜欢使用Spring/Hibernate架构的程序员来说一定对这部分非常熟悉。Juergen Hoeler也是《J2EE Development without EJB》一书的共同作者之一。

K



Kent Beck

设计模式的开创者之一。XP[eXtreme Programming(极限编程)]和TDD的创始人,xUnit的开发者。是《The Smalltalk Best Practice Patterns》、《Extreme Programming Explained》和《Planning Extreme Programming(与Martin Fowler合著)》等书的作者。

L


Linda DeMichiel

EJB 3.0规格主导者,在SUN工作。

M



Marc Fleury

博士,1968年生于巴黎。马克原先在太阳微视(法国)从事过销售工作。毕业于法国声名显赫的Ecole Poly技术学院的他,同时也是伞兵队的前任上尉。后来,马克从巴黎高等师范学校获得理论物理专业的硕士和博士学位。在从事物理方面的研究过程中,他也在麻省理工学院做过X射线激光器方面的访问学者。目前,马克是JBoss公司,即一个坐落在亚特兰大郊外的、提供优质服务的公司的总裁。JBoss公司,由Marc Fleury领衔的、由世界范围内100多位开发者组成的公司。他们分发各种用途的J2EE工具,并且致力于将JBoss发展为J2EE平台中的主流企业Java应用服务器。


Mark Hapner

Mark Hapner不仅是J2EE 1.4规范的主导者,还是Web Service协同工作组织中Sun公司的代表。简而言之,他是Sun驱动J2EE技术趋势的关键人物。Mark于1996年加 入Sun的Java软件公司,参与JDBC API的开发。接着,他撰写了EJB规范和JMS规范。


Martin Fowler

从80年代开始,他就一直从事软件开发的工作。他写过四本软件开发方面的书。《分析模式》是对他商业建模的经验的收集回顾,其中有很多重要的商业对象开发模式。《UML Disilled》是对UML符号、语意以及迭代式开发过程的概览,在1998年获得软件开发生产力奖金,现在已经出到了第二版。《Refactoring》描述了如何以可控的、快速的方式改变现有软件的设计。他最近与Kent Beck合写的《Planning Extreme Programming》则描述了如何进行XP设计。这四本书被全世界的软件开发者奉为经典,尤其是后两本,让软件开发者们看到了快速、灵活的软件开发的可能性。他所描述的重构技术和基于重构的XP方法,被称为“软件开发史上的一次风暴”。Martin Fowler在许多软件开发的国际性会议上做过演讲。他还是OOPSLA、软件开发委员会、UML世界、XP2001、TOOLS等几个协会的会员。同时,他还是“分布式运算”杂志的专栏作家。现在,他又为“软件开发”杂志做顾问,同时还为“IEEE软件”写一个设计专栏。目前是ThoughtWorks(系统集成及顾问公司)的CEO。


Matt Raible

1997年毕业于Denver大学,获得俄语、国际商业和经济学位。《Spring live》一书的作者。


Mike Cannon-Brookes

OpenSymphony及Atlassian的开发者,《Java Open Source programing》一书的作者。

P



Pat Lightbody

Webwork的开发者。


Patrick Linskey

JDO活跃人士,JDO2.0,EJB3.0专家组成员。

R



Rick Ross

Javalobby公司创建人。


Rickard Oberg

Xdoclet及Webwork的开发者,Jboss的前架构师,目前主要研究AOP。Oberg是瑞典Java编程竞赛“Software Reuse Cafe”的两度折桂者,这使得他成为瑞典最好的Java程序员之一。


Robin Roos

JDO2.0活跃人士,《Java Data Object》一书的作者。


Rod Johnson

Rod Johnson在2002年出版了一本非常畅销的J2EE书籍《Expert One-on-One J2EE Design and Development》,阐述了J2EE开发的方方面面的经验和设计,同时他根据本书的思路,开发了SpringFramework。如今SpringFramework是最流行的轻量级Java IoC容器。Rod本人也是Servlet2.4和JDO2.0专家委员会成员,他同时也是一位经验丰富的技术咨询专家。Rod开了一家咨询公司,提供SpringFramework的技术支持和培训。Rod Johnson也是反EJB方面一个代表人物,他创建的Spring的最终目标是取代EJB。

S



Scott Ambler

Scott W. Ambler是Ronin International的总裁,该公司是一家专门提供面向对象过程指导、体系结构建模和Enterprise JavaBean(EJB)开发的咨询企业。他自己著作了或者与其他人合著了几本有关面向对象开发的书籍,包括最近出版的《The Object Primer 2nd Edition》。可以通过scott.ambler@ronin-intl.com与他联系,他的网站位于www.ambysoft.com。


Sergey Dmitriev

Jetbrains公司CEO,Intelij IDEA的开发者。Sergey Dmitriev认为,我们今天把领域问题映射成通用编程语言如Java、C#,就像把C语言用汇编代码表达出来一样如在石器时代。所以我们需要可以随意制造贴近问题域的DSL。

T


Ted Neward

Ted Neward是Manning出版社元老级的作者,Manning最早出版的书正是Ted Neward的《Core OWL》与《Advanced OWL》(一本入门,一本进阶)。有趣的是,当Ted Neward的OWL这两本书快出版时,Borland居然宣布停止开发OWL。Ted Neward花了这么多心血,居然换来这样的结果。OWL本来市场就很小,又被Borland宣布死刑,Ted Neward的这两本书卖得奇惨。后来,Ted Neward转向Java,在Manning出版了一本很受好评的《Effective Enterprise Java》。接着,Ted Neward开始和O’Reilly合作,出版了好几本与他人合著的.NET书,包括了《C# in a Nutshell》、《VB.NET Core Classes in a Nutshell》、《C# Language Packet Reference》、《Shared Source CLI Essentials》。其中,《Shared Source CLI Essentials》一书是剖析Rotor的第一本书,2003年三月底出版。

V



Vincent Massol

Vincent Massol是Jakarta Cactus测试框架的创建者,也是Maven和MockObjects开发团队的活跃参与者。他是Pivolis的CTO,还是一位敏捷软件开发专家。《Junit in action》一书的作者。

RSS自动发现

四月 17, 2005

软件维护:Java文件格式之变化

一、概述

二、Java串行化

三、引入版本编号

四、结束语

一、概述

一个程序正式发行出去之后,如果要增加一些新的功能,往往意味着同时要修改用户保存数据的方式,也就是必须更改程序保存文件的格式――通常是增加保存到文件的数据。有些时候,文件格式必须作彻底的改动,以配合实现程序的新功能。从这个意义上看,文件格式的发展/变化总是和程序的功能改进相呼应。

但是,大多数情况下,把原有的数据格式一丢了事是行不通的。动物王国中,不能适应环境意味着死亡;软件领域也相似,新软件是否支持原有的数据格式很大程度上决定了用户是否升级。

不管软件新增/改进了多少功能,不管新的文件格式是多么完美,如果新软件不能利用原来的文件格式,用户一般不太会认可新软件。解决该问题的办法包括:

●保留老代码来读取老文件。采用这种方案一般需要额外编写一些代码,把老文件转换成新的格式(一般地,最简单的办法是先把老文件的数据转换成新的内部对象,然后利用现有的写入新版文件格式的对象)。这种办法的好处是既保留了原有的代码,又使它与新的文件格式兼容。但是,这种办法有时可能导致丢失部分数据,不过总要比丢失全部数据好。

●使新版软件能够读/写老文件格式。这种办法工作量较大,因为程序的新版本一般会增加一些原来没有的功能,老的数据格式中通常缺乏新功能必需的某些数据。

当新版软件对原来执行任务的方式作了根本性的变动时,丢失数据决非难得一见的偶然事件。如果新版软件采用和原来不同的方式达到同样的效果,原来的功能可能不再有保留的必要。例如,如果一个程序原来用Swing做用户界面,现在把它改成了Web(浏览器)用户界面,原来的许多用户界面设置就不再有效。

又如,如果有一个邮件程序,原来用的是以文件夹为基础的索引,现在把它改成了以单词为基础的索引系统,在升级索引文件格式的过程中就有可能丢失许多信息;如果原来的索引文件保存了许多用户配置选项和优化措施,在新的索引系统中这些数据可能无法利用。

这类问题没有绝对完美的解决办法,但是我们可以采取一些措施,使得升级文件格式带来的负面影响尽可能小。Java串行化(Serialization)有着简单易用的特点,日益成为一种保存文件的重要手段,有鉴于此,下面我们就来看看在软件版本变更过程中,通过Java串行化保存的文件如何保持兼容性。

二、Java串行化

Java串行化有许多优点:

●容易使用。

●如果一个对象连接到其他对象,串行化机制会保存所有相关的对象。

●如果某个对象出现多次,串行化机制只保存一次。这一点极为重要,它不仅减小了文件空间,而且即使代码写得不是很老练,也不必担心会出现无限循环(一个不老练的例子是,用递归的方式保存各个对象,却又未能有效审计哪些对象已经保存,这时就有可能陷入永无终止的循环)。

遗憾的是,Java串行化机制定义的文件格式似乎很脆弱,只要稍微改动一下类的定义,原来保存的对象就可能无法读取。例如,下面是一个简单的类定义:

public class Save implements Serializable
{
String name;

public void save() throws IOException
{
FileOutputStream f = new FileOutputStream("foo");
ObjectOutputStream oos = new ObjectOutputStream(f);
oos.writeObject(this);
oos.close();
}
}

如果在这个类定义中增加一个域,例如final int val = 7;,再来读取原来保存的对象,就会出现下面的异常:

java.io.InvalidClassException:
Save; local class incompatible:
stream classdesc serialVersionUID = -2805284943658356093,
local class serialVersionUID = 3419534311899376629

上例异常信息中的数字串表示类定义里各种属性的编码值:

●类的名字(Save)。

●域的名字(name)。

●方法的名字(Save)。

●已实现的接口(Serializable)。

改动上述任意一项内容(无论是增加或删除),都会引起编码值变化,从而引起类似的异常警报。这个数字序列称为“串行化版本统一标识符”(serial version universal identifier),简称UID。解决这个问题的办法是在类里面新增一个域serialVersionUID,强制类仍旧使用原来的UID。新增的域必须是:

●static:该域定义的属性作用于整个类,而非特定的对象。

●final:保证代码运行期间该域不会被修改。

●long:它是一个64位的数值。

也就是说,新增的serialVersionUID必须定义成下面这种形式:static final long serialVersionUID=-2805284943658356093L;。其中数字后面加上的L表示这是一个long值。

当然,改动之后的类不一定能够和原来的对象兼容。例如,如果把一个域的定义从String改成了int,执行逆-串行化操作时系统就不知道如何处理该值,显示出错误信息:java.io.InvalidClassException: Save; incompatible types for field name。

Java串行化规范(http://java.sun.com/j2se/1.4.1/docs/guide/

serialization/spec/serialTOC.doc.html)提供了有关兼容的改动(http://java.sun.com/j2se/1.4.1/docs/

guide/serialization/spec/version.doc7.html)和不兼容改动(http://java.sun.com/j2se/1.4.1/docs/guide/

serialization/spec/version.doc8.html)的清单,这些清单指出了对类作了哪些改动之后仍可能读取原来串行化的数据。具体细节比较复杂,但了解其主要机制还是很容易的:

简而言之,如果文件中确实保存了所有必需的数据,那么仍有可能读取该文件,当然前提是必须处理好串行化的UID。

三、引入版本编号

许多程序都在无意之中作出了这样的假设:这种文件格式是我要用到的最后一种格式,以后不再需要制定新的格式,现在要做的是处理好在此之前的各种格式。这种程序会试图读取格式版本更高的文件,操作进行到一半才发现某些不能识别的数据,然后就是突然崩溃。如果文件包含了大量的元数据(描述文件本身的数据),处理起来就要容易得多。

在Java中,每一个域都由其名称显式标明,只要文件的改动不是很大(只添加了域,没有被删除或作重大更改的域),可以想象,用老软件来读取新文件格式不是什么难事,虽然有可能丢失一些信息,但可以搞清楚文件的基本情况。

文件格式随着程序功能的改变而改变。理想情况下,程序应当做到既向后兼容(新的版本能够按照老版本的格式读取,甚至可能允许更新),同时做到向前兼容(较老的软件能够识别和处理新版的文件格式)。

通常,文件的版本无法从表面上一眼看出。大多数程序不会因为文件的版本不同而更改文件扩展名,而且目前尚无统一的标记文件版本的办法。因此,有关文件格式的版本声明只能在文件本身之内进行。如果你现在使用的文件格式还不包含版本声明,最好在下次把文件升级成一个不兼容的版本时马上加入版本标记,或者寻求一种在当前文件格式中加入版本标记但不会带来负面影响的办法。

版本信息一般在文件的开头声明,这是因为程序必须在处理文件之前首先检查文件的版本,除非确定了文件的版本,否则不必读取文件的其余部分。

按照惯例,文件版本编号包含两个部分:主版本编号和次版本编号。一个特定版本的程序应当有最适合它处理的主-次版本号;主版本号变化意味着文件格式的重大变化,要继续使用已经非常困难,必须作出重大修改才能升级到新的版本。

文件的主次版本号之前往往还可以加入另一项内容,称为“魔术数字”,它的作用就是保证程序处理的文件类型不会有误(因为文件扩展名有可能不能唯一地标明文件类型)。例如,Java的类文件总是以下列字节内容开头(十六进制):CA FE BA BE。目前还没有这类数字的统一注册机构,不过UNIX在/etc/magic下提供了一个清单(但并不完整)。魔术数字一般有四个字节,取值范围很大,所以一般不必担心会出现取值冲突的情形。

在编写和维护必须读/写文件的代码时,注意代码的向前/向后兼容性是非常必要的。在处理文件的代码中首先读取文件版本,然后根据版本号将文件剩余内容传递给适当的处理方法;如果文件的版本太老,已不再支持,程序应当给出明确的提示。

四、结束语

文件格式设计是一个极其重要的话题,但本文还有许多细节问题尚未涉及。例如,对于大型文件,我们需要随机访问,而不是从前向后依次读取文件内容的顺序访问,这样就不必为了访问文件最后几个字节而读取整个文件。无论是XML还是Java串行化对这类随机访问的支持都不是很理想,而且这类文件格式的发展变化比普通文件更难管理,因为他们依赖于字节级的访问,稍微改动一下文件格式就可能导致不兼容。

如果要让文件具有ACID特性――Atomicity、Consistency、Isolation和Durability,即原子性、一致性、隔离性、持久性,问题更加复杂。ACID与事务的概念密切相关,支持多用户同时访问一个文件。对于这类文件,可以考虑采用某种小型的数据库系统,例如Birdstep或Sleepycat。不过这已经进入了文件格式管理的另一个领域,既涉及到数据库管理软件的版本,也涉及到数据模式设计的版本。

撇开这些复杂的问题不谈,在实践中,很多时候我们只需简单的文件来保存数据,而且不会出现多用户并发访问,可以一次性地处理整个文件(或者至少适合使用顺序访问方式)。对于这些情形,最好在设计文件格式时就考虑版本问题,在日后的运行、维护中一定会带来不少方便。

【阅读原文】《
71EA82}/session_id~{A3FE3724-09D8-4AC2-B35E-21558DB8D582}/content/index.

asp”>Software Maintenance File Format Evolution in Java》

下一页 »