﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-苍穹之铁十字</title><link>http://www.blogjava.net/kuxiaoku/</link><description>收藏</description><language>zh-cn</language><lastBuildDate>Thu, 14 May 2026 04:55:43 GMT</lastBuildDate><pubDate>Thu, 14 May 2026 04:55:43 GMT</pubDate><ttl>60</ttl><item><title>Java正则表达式详解</title><link>http://www.blogjava.net/kuxiaoku/archive/2007/07/21/131668.html</link><dc:creator>苦笑枯</dc:creator><author>苦笑枯</author><pubDate>Sat, 21 Jul 2007 14:18:00 GMT</pubDate><guid>http://www.blogjava.net/kuxiaoku/archive/2007/07/21/131668.html</guid><wfw:comment>http://www.blogjava.net/kuxiaoku/comments/131668.html</wfw:comment><comments>http://www.blogjava.net/kuxiaoku/archive/2007/07/21/131668.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kuxiaoku/comments/commentRss/131668.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kuxiaoku/services/trackbacks/131668.html</trackback:ping><description><![CDATA[<strong>仙人掌工作室</strong><br>如果你曾经用过Perl或任何其他内建正则表达式支持的语言，你一定知道用正则表达式处理文本和匹配模式是多么简单。如果你不熟悉这个术语，那么&#8220;正则表达式&#8221;（Regular Expression）就是一个字符构成的串，它定义了一个用来搜索匹配字符串的模式。
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            许多语言，包括Perl、PHP、Python、JavaScript和JScript，都支持用正则表达式处理文本，一些文本编辑器用正则表达式实现高
            级&#8220;搜索-替换&#8221;功能。那么Java又怎样呢？本文写作时，一个包含了用正则表达式进行文本处理的Java规范需求（Specification
            Request）已经得到认可，你可以期待在JDK的下一版本中看到它。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            然而，如果现在就需要使用正则表达式，又该怎么办呢？你可以从Apache.org下载源代码开放的Jakarta-ORO库。本文接下来的内容先简要地介绍正则表达式的入门知识，然后以Jakarta-ORO API为例介绍如何使用正则表达式。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <strong><font size="4">
            一、正则表达式基础知识</font></strong> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            我们先从简单的开始。假设你要搜索一个包含字符&#8220;cat&#8221;的字符串，搜索用的正则表达式就是&#8220;cat&#8221;。如果搜索对大小写不敏感，单词&#8220;catalog&#8221;、&#8220;Catherine&#8221;、&#8220;sophisticated&#8221;都可以匹配。也就是说： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_a.jpg" border="0"> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <strong>
            1.1 句点符号</strong> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            假设你在玩英文拼字游戏，想要找出三个字母的单词，而且这些单词必须以&#8220;t&#8221;字母开头，以&#8220;n&#8221;字母结束。另外，假设有一本英文字典，你可以用正则表达式
            搜索它的全部内容。要构造出这个正则表达式，你可以使用一个通配符——句点符号&#8220;.&#8221;。这样，完整的表达式就是&#8220;t.n&#8221;，它匹配&#8220;tan&#8221;、
            &#8220;ten&#8221;、&#8220;tin&#8221;和&#8220;ton&#8221;，还匹配&#8220;t#n&#8221;、&#8220;tpn&#8221;甚至&#8220;t
            n&#8221;，还有其他许多无意义的组合。这是因为句点符号匹配所有字符，包括空格、Tab字符甚至换行符： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_b.jpg" border="0"> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <strong>
            1.2 方括号符号</strong> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            为了解决句点符号匹配范围过于广泛这一问题，你可以在方括号（&#8220;[]&#8221;）里面指定看来有意义的字符。此时，只有方括号里面指定的字符才参与匹配。也就是
            说，正则表达式&#8220;t[aeio]n&#8221;只匹配&#8220;tan&#8221;、&#8220;Ten&#8221;、&#8220;tin&#8221;和&#8220;ton&#8221;。但&#8220;Toon&#8221;不匹配，因为在方括号之内你只能匹配单个字
            符： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_c.jpg" border="0"></td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <strong>
            1.3 &#8220;或&#8221;符号</strong> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            如果除了上面匹配的所有单词之外，你还想要匹配&#8220;toon&#8221;，那么，你可以使用&#8220;|&#8221;操作符。&#8220;|&#8221;操作符的基本意义就是&#8220;或&#8221;运算。要匹配
            &#8220;toon&#8221;，使用&#8220;t(a|e|i|o|oo)n&#8221;正则表达式。这里不能使用方扩号，因为方括号只允许匹配单个字符；这里必须使用圆括号&#8220;()&#8221;。圆括
            号还可以用来分组，具体请参见后面介绍。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_d.jpg" border="0"> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <strong>
            1.4 表示匹配次数的符号</strong> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            表一显示了表示匹配次数的符号，这些符号用来确定紧靠该符号左边的符号出现的次数： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4n.jpg" border="0"></p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            假设我们要在文本文件中搜索美国的社会安全号码。这个号码的格式是999-99-9999。用来匹配它的正则表达式如图一所示。在正则表达式中，连字符
            （&#8220;-&#8221;）有着特殊的意义，它表示一个范围，比如从0到9。因此，匹配社会安全号码中的连字符号时，它的前面要加上一个转义字符&#8220;\&#8221;。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4a.gif" border="0">
            </p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">
            图一：匹配所有123-12-1234形式的社会安全号码</p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            假设进行搜索的时候，你希望连字符号可以出现，也可以不出现——即，999-99-9999和999999999都属于正确的格式。这时，你可以在连字符号后面加上&#8220;？&#8221;数量限定符号，如图二所示： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4b.gif" border="0">
            </p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">
            图二：匹配所有123-12-1234和123121234形式的社会安全号码</p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            下面我们再来看另外一个例子。美国汽车牌照的一种格式是四个数字加上二个字母。它的正则表达式前面是数字部分&#8220;[0-9]{4}&#8221;，再加上字母部分&#8220;[A-Z]{2}&#8221;。图三显示了完整的正则表达式。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4c.gif" border="0">
            </p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">
            图三：匹配典型的美国汽车牌照号码，如8836KV</p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            1.5 &#8220;否&#8221;符号 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            &#8220;^&#8221;符号称为&#8220;否&#8221;符号。如果用在方括号内，&#8220;^&#8221;表示不想要匹配的字符。例如，图四的正则表达式匹配所有单词，但以&#8220;X&#8221;字母开头的单词除外。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4d.gif" border="0">
            </p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">
            图四：匹配所有单词，但&#8220;X&#8221;开头的除外</p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            1.6 圆括号和空白符号 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            假设要从格式为&#8220;June 26, 1951&#8221;的生日日期中提取出月份部分，用来匹配该日期的正则表达式可以如图五所示： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4e.gif" border="0">
            </p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">
            图五：匹配所有Moth DD,YYYY格式的日期</p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            新出现的&#8220;\s&#8221;符号是空白符号，匹配所有的空白字符，包括Tab字符。如果字符串正确匹配，接下来如何提取出月份部分呢？只需在月份周围加上一个圆括号创建一个组，然后用ORO API（本文后面详细讨论）提取出它的值。修改后的正则表达式如图六所示： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4f.gif" border="0">
            </p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">
            图六：匹配所有Month DD,YYYY格式的日期，定义月份值为第一个组</p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <strong>
            1.7 其它符号</strong> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            为简便起见，你可以使用一些为常见正则表达式创建的快捷符号。如表二所示： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            表二：常用符号 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4o.jpg" border="0"> </p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            例如，在前面社会安全号码的例子中，所有出现&#8220;[0-9]&#8221;的地方我们都可以使用&#8220;\d&#8221;。修改后的正则表达式如图七所示： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4g.gif" border="0">
            </p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">图七：匹配所有123-12-1234格式的社会安全号码</p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <strong><font size="4">
            二、Jakarta-ORO库</font></strong> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            有许多源代码开放的正则表达式库可供Java程序员使用，而且它们中的许多支持Perl
            5兼容的正则表达式语法。我在这里选用的是Jakarta-ORO正则表达式库，它是最全面的正则表达式API之一，而且它与Perl
            5正则表达式完全兼容。另外，它也是优化得最好的API之一。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            Jakarta-ORO库以前叫做OROMatcher，Daniel Savarese大方地把它赠送给了Jakarta Project。你可以按照本文最后参考资源的说明下载它。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            我首先将简要介绍使用Jakarta-ORO库时你必须创建和访问的对象，然后介绍如何使用Jakarta-ORO API。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <strong>
            ▲ PatternCompiler对象</strong> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            首先，创建一个Perl5Compiler类的实例，并把它赋值给PatternCompiler接口对象。Perl5Compiler是PatternCompiler接口的一个实现，允许你把正则表达式编译成用来匹配的Pattern对象。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_e.jpg" border="0"> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <strong>
            ▲ Pattern对象</strong> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            要把正则表达式编译成Pattern对象，调用compiler对象的compile()方法，并在调用参数中指定正则表达式。例如，你可以按照下面这种方式编译正则表达式&#8220;t[aeio]n&#8221;： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_f.jpg" border="0"> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            默认情况下，编译器创建一个大小写敏感的模式（pattern）。因此，上面代码编译得到的模式只匹配&#8220;tin&#8221;、&#8220;tan&#8221;、 &#8220;ten&#8221;和&#8220;ton&#8221;，但不匹配&#8220;Tin&#8221;和&#8220;taN&#8221;。要创建一个大小写不敏感的模式，你应该在调用编译器的时候指定一个额外的参数： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_g.jpg" border="0"> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            创建好Pattern对象之后，你就可以通过PatternMatcher类用该Pattern对象进行模式匹配。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <strong>
            ▲ PatternMatcher对象</strong> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            PatternMatcher对象根据Pattern对象和字符串进行匹配检查。你要实例化一个Perl5Matcher类并把结果赋值给
            PatternMatcher接口。Perl5Matcher类是PatternMatcher接口的一个实现，它根据Perl
            5正则表达式语法进行模式匹配： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_h.jpg" border="0"> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            使用PatternMatcher对象，你可以用多个方法进行匹配操作，这些方法的第一个参数都是需要根据正则表达式进行匹配的字符串： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            &#183;	boolean matches(String input, Pattern pattern)：当输入字符串和正则表达式要精确匹配时使用。换句话说，正则表达式必须完整地描述输入字符串。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            &#183;	boolean matchesPrefix(String input, Pattern pattern)：当正则表达式匹配输入字符串起始部分时使用。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            &#183;	boolean contains(String input, Pattern pattern)：当正则表达式要匹配输入字符串的一部分时使用（即，它必须是一个子串）。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            另外，在上面三个方法调用中，你还可以用PatternMatcherInput对象作为参数替代String对象；这时，你可以从字符串中最后一次匹配
            的位置开始继续进行匹配。当字符串可能有多个子串匹配给定的正则表达式时，用PatternMatcherInput对象作为参数就很有用了。用
            PatternMatcherInput对象作为参数替代String时，上述三个方法的语法如下： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            &#183;	boolean matches(PatternMatcherInput input, Pattern pattern) </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            &#183;	boolean matchesPrefix(PatternMatcherInput input, Pattern pattern) </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            &#183;	boolean contains(PatternMatcherInput input, Pattern pattern) </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <strong><font size="4">
            三、应用实例</font></strong> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            下面我们来看看Jakarta-ORO库的一些应用实例。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <strong>
            3.1 日志文件处理</strong> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            任务：分析一个Web服务器日志文件，确定每一个用户花在网站上的时间。在典型的BEA WebLogic日志文件中，日志记录的格式如下： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_i.jpg" border="0"></td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            分析这个日志记录，可以发现，要从这个日志文件提取的内容有两项：IP地址和页面访问时间。你可以用分组符号（圆括号）从日志记录提取出IP地址和时间标记。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            首先我们来看看IP地址。IP地址有4个字节构成，每一个字节的值在0到255之间，各个字节通过一个句点分隔。因此，IP地址中的每一个字节有至少一个、最多三个数字。图八显示了为IP地址编写的正则表达式： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4h.gif" border="0">
            </p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">
            图八：匹配IP地址</p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            IP地址中的句点字符必须进行转义处理（前面加上&#8220;\&#8221;），因为IP地址中的句点具有它本来的含义，而不是采用正则表达式语法中的特殊含义。句点在正则表达式中的特殊含义本文前面已经介绍。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            日志记录的时间部分由一对方括号包围。你可以按照如下思路提取出方括号里面的所有内容：首先搜索起始方括号字符（&#8220;[&#8221;），提取出所有不超过结束方括号字符（&#8220;]&#8221;）的内容，向前寻找直至找到结束方括号字符。图九显示了这部分的正则表达式。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4i.gif" border="0">
            </p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">
            图九：匹配至少一个字符，直至找到&#8220;]&#8221;</p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            现在，把上述两个正则表达式加上分组符号（圆括号）后合并成单个表达式，这样就可以从日志记录提取出IP地址和时间。注意，为了匹配&#8220;- -&#8221;（但不提取它），正则表达式中间加入了&#8220;\s-\s-\s&#8221;。完整的正则表达式如图十所示。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4j.gif" border="0">
            </p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">
            图十：匹配IP地址和时间标记</p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            现在正则表达式已经编写完毕，接下来可以编写使用正则表达式库的Java代码了。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            为使用Jakarta-ORO库，首先创建正则表达式字符串和待分析的日志记录字符串： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_j.jpg" border="0"> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            这里使用的正则表达式与图十的正则表达式差不多完全相同，但有一点例外：在Java中，你必须对每一个向前的斜杠（&#8220;\&#8221;）进行转义处理。图十不是
            Java的表示形式，所以我们要在每个&#8220;\&#8221;前面加上一个&#8220;\&#8221;以免出现编译错误。遗憾的是，转义处理过程很容易出现错误，所以应该小心谨慎。你可以首先
            输入未经转义处理的正则表达式，然后从左到右依次把每一个&#8220;\&#8221;替换成&#8220;\\&#8221;。如果要复检，你可以试着把它输出到屏幕上。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            初始化字符串之后，实例化PatternCompiler对象，用PatternCompiler编译正则表达式创建一个Pattern对象： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_k.jpg" border="0"> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            现在，创建PatternMatcher对象，调用PatternMatcher接口的contain()方法检查匹配情况： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_l.jpg" border="0"> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            接下来，利用PatternMatcher接口返回的MatchResult对象，输出匹配的组。由于logEntry字符串包含匹配的内容，你可以看到类如下面的输出： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_m.jpg" border="0"></td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <strong>
            3.2 HTML处理实例一</strong> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            下面一个任务是分析HTML页面内FONT标记的所有属性。HTML页面内典型的FONT标记如下所示： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <font color="red" face="Arial, serif" size="+2"> </font><img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_n.jpg" border="0"> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            程序将按照如下形式，输出每一个FONT标记的属性： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_o.jpg" border="0"> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            在这种情况下，我建议你使用两个正则表达式。第一个如图十一所示，它从字体标记提取出&#8220;"face="Arial, Serif" size="+2" color="red"&#8221;。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4k.gif" border="0">
            </p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">
            图十一：匹配FONT标记的所有属性</p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            第二个正则表达式如图十二所示，它把各个属性分割成名字-值对。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4l.gif" border="0">
            </p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">
            图十二：匹配单个属性，并把它分割成名字-值对</p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            分割结果为： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_p.jpg" border="0"> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            现在我们来看看完成这个任务的Java代码。首先创建两个正则表达式字符串，用Perl5Compiler把它们编译成Pattern对象。编译正则表达
            式的时候，指定Perl5Compiler.CASE_INSENSITIVE_MASK选项，使得匹配操作不区分大小写。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            接下来，创建一个执行匹配操作的Perl5Matcher对象。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_q.jpg" border="0"> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            假设有一个String类型的变量html，它代表了HTML文件中的一行内容。如果html字符串包含FONT标记，匹配器将返回true。此时，你可以用匹配器对象返回的MatchResult对象获得第一个组，它包含了FONT的所有属性： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_r.jpg" border="0"> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            接下来创建一个PatternMatcherInput对象。这个对象允许你从最后一次匹配的位置开始继续进行匹配操作，因此，它很适合于提取FONT标
            记内属性的名字-值对。创建PatternMatcherInput对象，以参数形式传入待匹配的字符串。然后，用匹配器实例提取出每一个FONT的属
            性。这通过指定PatternMatcherInput对象（而不是字符串对象）为参数，反复地调用PatternMatcher对象的contains
            ()方法完成。PatternMatcherInput对象之中的每一次迭代将把它内部的指针向前移动，下一次检测将从前一次匹配位置的后面开始。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            本例的输出结果如下： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_s.jpg" border="0"> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <strong>
            3.3 HTML处理实例二</strong> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            下面我们来看看另一个处理HTML的例子。这一次，我们假定Web服务器从widgets.acme.com移到了newserver.acme.com。现在你要修改一些页面中的链接： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_t.jpg" border="0"> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            执行这个搜索的正则表达式如图十三所示： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center"><img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4m.gif" border="0">
            </p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <p align="center">
            图十三：匹配修改前的链接</p>
            </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            如果能够匹配这个正则表达式，你可以用下面的内容替换图十三的链接： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_u.jpg" border="0"></td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            注意#字符的后面加上了$1。Perl正则表达式语法用$1、$2等表示已经匹配且提取出来的组。图十三的表达式把所有作为一个组匹配和提取出来的内容附加到链接的后面。 </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            现在，返回Java。就象前面我们所做的那样，你必须创建测试字符串，创建把正则表达式编译到Pattern对象所必需的对象，以及创建一个PatternMatcher对象：<img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_v.jpg" border="0"> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            接下来，用com.oroinc.text.regex包Util类的substitute()静态方法进行替换，输出结果字符串： </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            <img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_w.jpg" border="0"> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            Util.substitute()方法的语法如下： </td>
        </tr>
    </tbody>
</table>
<table align="center" height="17" width="620">
    <tbody>
        <tr>
            <td class="a14" height="13">
            <img  src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_x.jpg" border="0"> </td>
        </tr>
    </tbody>
</table>
<table align="center" width="620">
    <tbody>
        <tr>
            <td class="a14">
            这个调用的前两个参数是以前创建的PatternMatcher和Pattern对象。第三个参数是一个Substiution对象，它决定了替换操作如
            何进行。本例使用的是Perl5Substitution对象，它能够进行Perl5风格的替换。第四个参数是想要进行替换操作的字符串，最后一个参数允
            许指定是否替换模式的所有匹配子串（Util.SUBSTITUTE_ALL），或只替换指定的次数。 </td>
        </tr>
    </tbody>
</table>
<strong>【结束语】</strong>在
这篇文章中，我为你介绍了正则表达式的强大功能。只要正确运用，正则表达式能够在字符串提取和文本修改中起到很大的作用。另外，我还介绍了如何在Java
程序中通过Jakarta-ORO库利用正则表达式。至于最终采用老式的字符串处理方式（使用StringTokenizer，charAt，和
substring），还是采用正则表达式，这就有待你自己决定了。<img src ="http://www.blogjava.net/kuxiaoku/aggbug/131668.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kuxiaoku/" target="_blank">苦笑枯</a> 2007-07-21 22:18 <a href="http://www.blogjava.net/kuxiaoku/archive/2007/07/21/131668.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java 位运算</title><link>http://www.blogjava.net/kuxiaoku/archive/2007/06/16/124674.html</link><dc:creator>苦笑枯</dc:creator><author>苦笑枯</author><pubDate>Sat, 16 Jun 2007 10:13:00 GMT</pubDate><guid>http://www.blogjava.net/kuxiaoku/archive/2007/06/16/124674.html</guid><wfw:comment>http://www.blogjava.net/kuxiaoku/comments/124674.html</wfw:comment><comments>http://www.blogjava.net/kuxiaoku/archive/2007/06/16/124674.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/kuxiaoku/comments/commentRss/124674.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kuxiaoku/services/trackbacks/124674.html</trackback:ping><description><![CDATA[<p><strong>移位运算符</strong></p>
<p>&nbsp;&nbsp;&nbsp; 包括：<br>&nbsp;&nbsp;&nbsp; &#8220;&gt;&gt; 右移&#8221;；&#8220;&lt;&lt; 左移&#8221;；&#8220;&gt;&gt;&gt; 无符号右移&#8221;</p>
<p>例子：<br>-5&gt;&gt;3=-1<br>1111 1111 1111 1111 1111 1111 1111 1011<br>1111 1111 1111 1111 1111 1111 1111 1111<br>其结果与 Math.floor((double)-5/(2*2*2)) 完全相同。</p>
<p>-5&lt;&lt;3=-40<br>1111 1111 1111 1111 1111 1111 1111 1011<br>1111 1111 1111 1111 1111 1111 1101 1000 <br>其结果与 -5*2*2*2 完全相同。</p>
<p>5&gt;&gt;3=0<br>0000 0000 0000 0000 0000 0000 0000 0101<br>0000 0000 0000 0000 0000 0000 0000 0000<br>其结果与 5/(2*2*2) 完全相同。</p>
<p>5&lt;&lt;3=40<br>0000 0000 0000 0000 0000 0000 0000 0101<br>0000 0000 0000 0000 0000 0000 0010 1000<br>其结果与 5*2*2*2 完全相同。</p>
<p>-5&gt;&gt;&gt;3=536870911&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>1111 1111 1111 1111 1111 1111 1111 1011<br>0001 1111 1111 1111 1111 1111 1111 1111</p>
<p>无论正数、负数，它们的右移、左移、无符号右移 32 位都是其本身，比如 -5&lt;&lt;32=-5、-5&gt;&gt;32=-5、-5&gt;&gt;&gt;32=-5。<br>一个有趣的现象是，把 1 左移 31 位再右移 31 位，其结果为 -1。<br>0000 0000 0000 0000 0000 0000 0000 0001<br>1000 0000 0000 0000 0000 0000 0000 0000<br>1111 1111 1111 1111 1111 1111 1111 1111</p>
<p><strong><br>位逻辑运算符</strong></p>
<p>&nbsp;&nbsp;&nbsp; 包括：<br>&nbsp;&nbsp;&nbsp; &amp; 与；| 或；~ 非（也叫做求反）；^ 异或</p>
<p>&nbsp;&nbsp;&nbsp; &#8220;&amp; 与&#8221;、&#8220;| 或&#8221;、&#8220;~ 非&#8221;是基本逻辑运算，由此可以演变出&#8220;与非&#8221;、&#8220;或非&#8221;、&#8220;与或非&#8221;复合逻辑运算。&#8220;^ 异或&#8221;是一种特殊的逻辑运算，对它求反可以得到&#8220;同或&#8221;，所以&#8220;同或&#8221;逻辑也叫&#8220;异或非&#8221;逻辑。</p>
<p>例子：<br>5&amp;3=1<br>0000 0000 0000 0000 0000 0000 0000 0101<br>0000 0000 0000 0000 0000 0000 0000 0011<br>0000 0000 0000 0000 0000 0000 0000 0001</p>
<p>-5&amp;3=1<br>1111 1111 1111 1111 1111 1111 1111 1011<br>0000 0000 0000 0000 0000 0000 0000 0011<br>0000 0000 0000 0000 0000 0000 0000 0011</p>
<p>5|3=7<br>0000 0000 0000 0000 0000 0000 0000 0101<br>0000 0000 0000 0000 0000 0000 0000 0011<br>0000 0000 0000 0000 0000 0000 0000 0111</p>
<p>-5|3=-5<br>1111 1111 1111 1111 1111 1111 1111 1011<br>0000 0000 0000 0000 0000 0000 0000 0011<br>1111 1111 1111 1111 1111 1111 1111 1011</p>
<p>~5=-6<br>0000 0000 0000 0000 0000 0000 0000 0101<br>1111 1111 1111 1111 1111 1111 1111 1010</p>
<p>~-5=4<br>1111 1111 1111 1111 1111 1111 1111 1011<br>0000 0000 0000 0000 0000 0000 0000 0100</p>
<p>5^3=6<br>0000 0000 0000 0000 0000 0000 0000 0101<br>0000 0000 0000 0000 0000 0000 0000 0011<br>0000 0000 0000 0000 0000 0000 0000 0110</p>
-5^3=-8<br>1111 1111 1111 1111 1111 1111 1111 1011<br>0000 0000 0000 0000 0000 0000 0000 0011<br>1111 1111 1111 1111 1111 1111 1111 1000<img src ="http://www.blogjava.net/kuxiaoku/aggbug/124674.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kuxiaoku/" target="_blank">苦笑枯</a> 2007-06-16 18:13 <a href="http://www.blogjava.net/kuxiaoku/archive/2007/06/16/124674.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Eclipse快速上手指南之使用ANT</title><link>http://www.blogjava.net/kuxiaoku/archive/2007/06/11/123389.html</link><dc:creator>苦笑枯</dc:creator><author>苦笑枯</author><pubDate>Mon, 11 Jun 2007 06:51:00 GMT</pubDate><guid>http://www.blogjava.net/kuxiaoku/archive/2007/06/11/123389.html</guid><wfw:comment>http://www.blogjava.net/kuxiaoku/comments/123389.html</wfw:comment><comments>http://www.blogjava.net/kuxiaoku/archive/2007/06/11/123389.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kuxiaoku/comments/commentRss/123389.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kuxiaoku/services/trackbacks/123389.html</trackback:ping><description><![CDATA[<div id="contitle">
<h1>Eclipse快速上手指南之使用ANT</h1>
</div>
<div id="conauthor"><span>
2004-07-30 17:35
</span><span>作者：
</span><span>出处：
J2ME开发网
</span><span>&nbsp;&nbsp;&nbsp; Ant是Java平台下非常棒的批处理命令执行程序，能非常方便地自动完成编译，测试，打包，部署等等一系列任务，大大提高开发效率。如果你现在还没有开始使用Ant，那就要赶快开始学习使用，使自己的开发水平上一个新台阶。<br></span></div>
<br>　　Eclipse中已经集成了Ant，我们可以直接在Eclipse中运行Ant。<br><br>　　以前面建立的Hello工程为例，创建以下目录结构：<br><br>
<table align="center" border="0" width="90%">
    <tbody>
        <tr>
            <td>
            <div align="center"><img src="http://www.yesky.com/image20010518/208897.jpg" onerror="this.src='http://www.yesky.com/image20010518/208897.jpg';" align="middle" border="1" hspace="3" vspace="1"></div>
            </td>
        </tr>
    </tbody>
</table>
<br>　　新建一个build.xml，放在工程根目录下。build.xml定义了Ant要执行的批处理命令。虽然Ant也可以使用其它文件名，但是遵循标准能更使开发更规范，同时易于与别人交流。<br><br>　　通常，src存放Java源文件，classes存放编译后的class文件，lib存放编译和运行用到的所有jar文件，web存放JSP等web文件，dist存放打包后的jar文件，doc存放API文档。<br><br>　　然后在根目录下创建build.xml文件，输入以下内容： <br><font color="#006400" face="Courier New"><br></font>
<table align="center" bgcolor="#d9ecee" border="1" bordercolor="#ffcc66" width="90%">
    <tbody>
        <tr>
            <td><font color="#006400" face="Courier New">＜?xml version="1.0"?＞<br>＜project name="Hello world" default="doc"＞</font><br><br><font color="#006400" face="Courier New">＜!-- properies --＞<br>＜property name="src.dir" value="src" /＞<br>＜property name="report.dir" value="report" /＞<br>＜property name="classes.dir" value="classes" /＞<br>＜property name="lib.dir" value="lib" /＞<br>＜property name="dist.dir" value="dist" /＞<br>＜property name="doc.dir" value="doc"/＞</font><br><br><font color="#006400" face="Courier New">＜!-- 定义classpath --＞<br>＜path id="master-classpath"＞<br>＜fileset file="${lib.dir}/*.jar" /＞<br>＜pathelement path="${classes.dir}"/＞<br>＜/path＞</font><br><br><font color="#006400" face="Courier New">＜!-- 初始化任务 --＞<br>＜target name="init"＞<br>＜/target＞</font><br><br><font color="#006400" face="Courier New">＜!-- 编译 --＞<br>＜target name="compile" depends="init" description="compile the source files"＞<br>＜mkdir dir="${classes.dir}"/＞<br>＜javac srcdir="${src.dir}" destdir="${classes.dir}" target="1.4"＞<br>＜classpath refid="master-classpath"/＞<br>＜/javac＞<br>＜/target＞</font><br><br><font color="#006400" face="Courier New">＜!-- 测试 --＞<br>＜target name="test" depends="compile" description="run junit test"＞<br>＜mkdir dir="${report.dir}"/＞<br>＜junit printsummary="on"<br>haltonfailure="false"<br>failureproperty="tests.failed"<br>showoutput="true"＞<br>＜classpath refid="master-classpath" /＞<br>＜formatter type="plain"/＞<br>＜batchtest todir="${report.dir}"＞<br>＜fileset dir="${classes.dir}"＞<br>＜include name="**/*Test.*"/＞<br>＜/fileset＞<br>＜/batchtest＞<br>＜/junit＞<br>＜fail if="tests.failed"＞<br>***********************************************************<br>**** One or more tests failed! Check the output ... ****<br>***********************************************************<br>＜/fail＞<br>＜/target＞</font><br><br><font color="#006400" face="Courier New">＜!-- 打包成jar --＞<br>＜target name="pack" depends="test" description="make .jar file"＞<br>＜mkdir dir="${dist.dir}" /＞<br>＜jar destfile="${dist.dir}/hello.jar" basedir="${classes.dir}"＞<br>＜exclude name="**/*Test.*" /＞<br>＜exclude name="**/Test*.*" /＞<br>＜/jar＞<br>＜/target＞</font><br><br><font color="#006400" face="Courier New">＜!-- 输出api文档 --＞<br>＜target name="doc" depends="pack" description="create api doc"＞<br>＜mkdir dir="${doc.dir}" /＞<br>＜javadoc destdir="${doc.dir}"<br>author="true"<br>version="true"<br>use="true"<br>windowtitle="Test API"＞<br>＜packageset dir="${src.dir}" defaultexcludes="yes"＞<br>＜include name="example/**" /＞<br>＜/packageset＞<br>＜doctitle＞＜![CDATA[＜h1＞Hello, test＜/h1＞]]＞＜/doctitle＞<br>＜bottom＞＜![CDATA[＜i＞All Rights Reserved.＜/i＞]]＞＜/bottom＞<br>＜tag name="todo" scope="all" description="To do:" /＞<br>＜/javadoc＞<br>＜/target＞<br>＜/project＞</font></td>
        </tr>
    </tbody>
</table>
<br>　　以上xml依次定义了init（初始化），compile（编译），test（测试），doc（生成文档），pack（打包）任务，可以作为模板。<br><br>　　选中Hello工程，然后选择&#8220;Project&#8221;，&#8220;Properties&#8221;，&#8220;Builders&#8221;，&#8220;New&#8230;&#8221;，选择&#8220;Ant Build&#8221;：<br><br>
<table align="center" border="0" width="90%">
    <tbody>
        <tr>
            <td>
            <div align="center"><img src="http://www.yesky.com/image20010518/208898.jpg" onerror="this.src='http://www.yesky.com/image20010518/208898.jpg';" align="middle" border="1" hspace="3" vspace="1"></div>
            </td>
        </tr>
    </tbody>
</table>
<br>
填入Name：Ant_Builder；Buildfile：build.xml；Base
Directory：${workspace_loc:/Hello}（按&#8220;Browse
Workspace&#8221;选择工程根目录），由于用到了junit.jar包，搜索Eclipse目录，找到junit.jar，把它复制到
Hello/lib目录下，并添加到Ant的Classpath中：<br><br>
<table align="center" border="0" width="90%">
    <tbody>
        <tr>
            <td>
            <div align="center"><img src="http://www.yesky.com/image20010518/208899.jpg" onerror="this.src='http://www.yesky.com/image20010518/208899.jpg';" align="middle" border="1" hspace="3" vspace="1"></div>
            </td>
        </tr>
    </tbody>
</table>
<br>　　然后在Builder面板中钩上Ant_Build，去掉Java Builder：<br><br>
<table align="center" border="0" width="90%">
    <tbody>
        <tr>
            <td>
            <div align="center"><img src="http://www.yesky.com/image20010518/208900.jpg" onerror="this.src='http://www.yesky.com/image20010518/208900.jpg';" align="middle" border="1" hspace="3" vspace="1"></div>
            </td>
        </tr>
    </tbody>
</table>
<br>　　再次编译，即可在控制台看到Ant的输出：<br><br>
<table align="center" bgcolor="#d9ecee" border="1" bordercolor="#ffcc66" width="90%">
    <tbody>
        <tr>
            <td><font color="#006400" face="Courier New">Buildfile: F:\eclipse-projects\Hello\build.xml</font><br><br><font color="#006400" face="Courier New">init:</font><br><br><font color="#006400" face="Courier New">compile:<br>[mkdir] Created dir: F:\eclipse-projects\Hello\classes<br>[javac] Compiling 2 source files to F:\eclipse-projects\Hello\classes</font><br><br><font color="#006400" face="Courier New">test:<br>[mkdir] Created dir: F:\eclipse-projects\Hello\report<br>[junit] Running example.HelloTest<br>[junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.02 sec</font><br><br><font color="#006400" face="Courier New">pack:<br>[mkdir] Created dir: F:\eclipse-projects\Hello\dist<br>[jar] Building jar: F:\eclipse-projects\Hello\dist\hello.jar</font><br><br><font color="#006400" face="Courier New">doc:<br>[mkdir] Created dir: F:\eclipse-projects\Hello\doc<br>[javadoc] Generating Javadoc<br>[javadoc] Javadoc execution<br>[javadoc] Loading source files for package example...<br>[javadoc] Constructing Javadoc information...<br>[javadoc] Standard Doclet version 1.4.2_04<br>[javadoc] Building tree for all the packages and classes...<br>[javadoc] Building index for all the packages and classes...<br>[javadoc] Building index for all classes...<br>[javadoc] Generating F:\eclipse-projects\Hello\doc\stylesheet.css...<br>[javadoc]
            Note: Custom tags that could override future standard tags: @todo. To
            avoid potential overrides, use at least one period character (.) in
            custom tag names.<br>[javadoc] Note: Custom tags that were not seen: @todo<br>BUILD SUCCESSFUL<br>Total time: 11 seconds</font></td>
        </tr>
    </tbody>
</table>
<br>
Ant依次执行初始化，编译，测试，打包，生成API文档一系列任务，极大地提高了开发效率。将来开发J2EE项目时，还可加入部署等任务。并且，即使
脱离了Eclipse环境，只要正确安装了Ant，配置好环境变量ANT_HOME=＜Ant解压目录＞，Path=&#8230;;%ANT_HOME%\bin，
在命令行提示符下切换到Hello目录，简单地键入ant即可。<img src ="http://www.blogjava.net/kuxiaoku/aggbug/123389.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kuxiaoku/" target="_blank">苦笑枯</a> 2007-06-11 14:51 <a href="http://www.blogjava.net/kuxiaoku/archive/2007/06/11/123389.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ant打包一记</title><link>http://www.blogjava.net/kuxiaoku/archive/2007/06/11/123388.html</link><dc:creator>苦笑枯</dc:creator><author>苦笑枯</author><pubDate>Mon, 11 Jun 2007 06:49:00 GMT</pubDate><guid>http://www.blogjava.net/kuxiaoku/archive/2007/06/11/123388.html</guid><wfw:comment>http://www.blogjava.net/kuxiaoku/comments/123388.html</wfw:comment><comments>http://www.blogjava.net/kuxiaoku/archive/2007/06/11/123388.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kuxiaoku/comments/commentRss/123388.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kuxiaoku/services/trackbacks/123388.html</trackback:ping><description><![CDATA[<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td valign="top"><span class="arttitle">ant打包一记</span></td>
        </tr>
        <tr>
            <td class="details" align="right" valign="top">By&nbsp; <a  href="http://www.blueidea.com/bbs/viewuser.asp?username=%E5%87%8C%E4%BA%91%E5%BF%97" target="_blank" class="biuser">凌云志</a> 发表于 2007-6-10 13:21:00&nbsp; </td>
        </tr>
        <tr>
            <td class="artbody" valign="top"><br>
            <p>以前对于ant的使用总是避而不触，总以为有点难度，最近一直看我们项目中的build.xml忽而觉得非常简单，也模仿着在我的<a  href="http://www.javaedu.com/">www.javaedu.com</a>开发上使用了一下，非常不错，以下是我的打包文件build.xml：<br><br>&lt;?xml version="1.0"?&gt;<br>&nbsp;<br>&lt;project name="payManager" default="all" basedir="."&gt;<br>&nbsp;<br>&nbsp;&lt;property name="src.dir"&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;value="JavaSource" /&gt;<br>&nbsp;&lt;property name="classes.dir" &nbsp;&nbsp;value="WebContent/WEB-INF/classes" /&gt;<br>&nbsp;&lt;property name="lib.dir"&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;value="WebContent/WEB-INF/lib" /&gt;<br>&nbsp;&lt;property name="WebContent.dir"&nbsp;&nbsp;&nbsp;&nbsp; value="WebContent" /&gt;<br>&nbsp;<br>&nbsp;&lt;!--用于输出的临时文件夹与打包的文件夹--&gt;<br>&nbsp;&lt;property name="temp.dir"&nbsp;&nbsp;&nbsp;&nbsp; value="D:\temp" /&gt;<br>&nbsp;&lt;property name="war.dir"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value="D:\war" /&gt;</p>
            <p>&nbsp;&lt;!--对于不同环境的war包，使用不同的配置文件--&gt;<br>&nbsp;&lt;property name="生产.dir"&nbsp;&nbsp;&nbsp;&nbsp; value="bak\生产" /&gt;<br>&nbsp;&lt;property name="开发.dir"&nbsp;&nbsp;&nbsp;&nbsp; value="bak\开发" /&gt;<br>&nbsp;<br>&nbsp;&lt;!-- 定义classpath --&gt;<br>&nbsp;&lt;path id="master-classpath"&gt;<br>&nbsp;&nbsp;&lt;fileset file="${lib.dir}/*.jar" /&gt;<br>&nbsp;&nbsp;&lt;pathelement path="${classes.dir}" /&gt;<br>&nbsp;&lt;/path&gt;</p>
            <p>&nbsp;&lt;target name="clean"&gt;&nbsp;<br>&nbsp;&nbsp;&lt;delete dir="${temp.dir}" /&gt;<br>&nbsp;&nbsp;&lt;delete dir="${classes.dir}" /&gt;<br>&nbsp;&nbsp;&lt;delete file="${war.dir}/开发/ROOT.war"/&gt;<br>&nbsp;&nbsp;&lt;delete file="${war.dir}/生产/ROOT.war"/&gt;<br>&nbsp;&lt;/target&gt;</p>
            <p>&nbsp;&lt;!-- 初始化任务 --&gt;<br>&nbsp;&lt;target name="init" depends="clean"&gt;<br>&nbsp;&lt;/target&gt;</p>
            <p>&nbsp;&lt;!-- 编译 --&gt;<br>&nbsp;&lt;target name="compile" depends="init" description="compile the source files"&gt;<br>&nbsp;&nbsp;&lt;mkdir dir="${temp.dir}/生产" /&gt;<br>&nbsp;&nbsp;&lt;mkdir dir="${temp.dir}/开发" /&gt;&nbsp;&nbsp;<br>&nbsp;&nbsp;&lt;mkdir dir="${classes.dir}" /&gt;</p>
            <p>&nbsp;&nbsp;&lt;javac srcdir="${src.dir}" destdir="${classes.dir}"&nbsp; debug="true" encoding="GB2312"&gt;<br>&nbsp;&nbsp;&nbsp;&lt;classpath refid="master-classpath" /&gt;<br>&nbsp;&nbsp;&lt;/javac&gt;</p>
            <p>&nbsp;&nbsp;&lt;copy todir="${temp.dir}/生产" overwrite="true"&gt;<br>&nbsp;&nbsp;&nbsp;&lt;fileset dir="${WebContent.dir}"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="**/**" /&gt;<br>&nbsp;&nbsp;&nbsp;&lt;/fileset&gt;<br>&nbsp;&nbsp;&lt;/copy&gt;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&lt;copy todir="${temp.dir}/生产/WEB-INF/classes" overwrite="true"&gt;<br>&nbsp;&nbsp;&nbsp;&lt;fileset dir="${生产.dir}"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="jlo_logging.xml" /&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="log4j.properties" /&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="mvncore.xml" /&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="mvnForum_i18n_zh_CN.properties" /&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="mvnforum.xml" /&gt;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="whirlycache.xml" /&gt;<br>&nbsp;&nbsp;&nbsp;&lt;/fileset&gt;<br>&nbsp;&nbsp;&lt;/copy&gt;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&lt;copy todir="${temp.dir}/开发" overwrite="true"&gt;<br>&nbsp;&nbsp;&nbsp;&lt;fileset dir="${WebContent.dir}"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="**/**" /&gt;<br>&nbsp;&nbsp;&nbsp;&lt;/fileset&gt;<br>&nbsp;&nbsp;&lt;/copy&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&lt;copy todir="${temp.dir}/开发/WEB-INF/classes" overwrite="true"&gt;<br>&nbsp;&nbsp;&nbsp;&lt;fileset dir="${开发.dir}"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="jlo_logging.xml" /&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="log4j.properties" /&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="mvncore.xml" /&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="mvnForum_i18n_zh_CN.properties" /&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="mvnforum.xml" /&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="whirlycache.xml" /&gt;<br>&nbsp;&nbsp;&nbsp;&lt;/fileset&gt;<br>&nbsp;&nbsp;&lt;/copy&gt;<br>&nbsp;&nbsp;<br>&nbsp;&lt;/target&gt;</p>
            <p>&nbsp;&lt;!--打包--&gt;<br>&nbsp;&lt;target name="war" depends="compile"&gt;<br>&nbsp;&nbsp;&lt;mkdir dir="${war.dir}/生产" /&gt;<br>&nbsp;&nbsp;&lt;mkdir dir="${war.dir}/开发" /&gt;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&lt;jar jarfile="${war.dir}/生产/ROOT.war"&gt;<br>&nbsp;&nbsp;&nbsp;&lt;fileset dir="${temp.dir}/生产"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="**/*" /&gt;<br>&nbsp;&nbsp;&nbsp;&lt;/fileset&gt;<br>&nbsp;&nbsp;&lt;/jar&gt;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&lt;jar jarfile="${war.dir}/开发/ROOT.war"&gt;<br>&nbsp;&nbsp;&nbsp;&lt;fileset dir="${temp.dir}/开发"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="**/*" /&gt;<br>&nbsp;&nbsp;&nbsp;&lt;/fileset&gt;<br>&nbsp;&nbsp;&lt;/jar&gt;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&lt;delete dir="${temp.dir}"/&gt;<br>&nbsp;&lt;/target&gt;<br>&nbsp;<br>&nbsp;&lt;target name="all" depends="war"&gt;<br>&nbsp;&nbsp;&lt;delete dir="${classes.dir}" /&gt;<br>&nbsp;&nbsp;&lt;delete dir="${temp.dir}" /&gt;<br>&nbsp;&lt;/target&gt;</p>
            <p>&lt;/project&gt;</p>
            <p>值得注意的是，在书写build.xml的时候一定要小心，别写错了，我就是因为粗心，在写下面代码的时候：<br><br>&nbsp;&nbsp;&nbsp;&lt;fileset dir="${生产.dir}"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong><font color="#ff0033">.&lt;include name="jlo_logging.xml" /&gt;</font></strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="log4j.properties" /&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="mvncore.xml" /&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="mvnForum_i18n_zh_CN.properties" /&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="mvnforum.xml" /&gt;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;include name="whirlycache.xml" /&gt;<br>&nbsp;&nbsp;&nbsp;&lt;/fileset&gt;<br><br>不小心在红色代码前加了一个&#8220;.&#8221;，结果报了一个<font color="#ff0033">type &nbsp; doesn't &nbsp; support &nbsp; nested &nbsp; text &nbsp; data.&nbsp;&nbsp; </font>的错，我找了半天没找出原因，到网上搜了一下竟然没有找到答案，后来才发现自己写错了，大汗，改正后，搞定，爽啊。是为记。</p>
            </td>
        </tr>
    </tbody>
</table><img src ="http://www.blogjava.net/kuxiaoku/aggbug/123388.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kuxiaoku/" target="_blank">苦笑枯</a> 2007-06-11 14:49 <a href="http://www.blogjava.net/kuxiaoku/archive/2007/06/11/123388.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ANT的安装/配置笔记</title><link>http://www.blogjava.net/kuxiaoku/archive/2007/06/11/123385.html</link><dc:creator>苦笑枯</dc:creator><author>苦笑枯</author><pubDate>Mon, 11 Jun 2007 06:44:00 GMT</pubDate><guid>http://www.blogjava.net/kuxiaoku/archive/2007/06/11/123385.html</guid><wfw:comment>http://www.blogjava.net/kuxiaoku/comments/123385.html</wfw:comment><comments>http://www.blogjava.net/kuxiaoku/archive/2007/06/11/123385.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kuxiaoku/comments/commentRss/123385.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kuxiaoku/services/trackbacks/123385.html</trackback:ping><description><![CDATA[<span class="post-footers">
作者：<a  href="http://www.chedong.com/">车东</a> 发表于：2003-03-06 17:03 最后更新于：2007-04-12 11:04<br>
<a  href="http://creativecommons.org/licenses/by/3.0/deed.zh">版权声明</a>：可以任意转载，转载时请务必以超链接形式标明文章<a  href="http://www.chedong.com/tech/ant.html" class="permalink">原始出处</a>和作者信息及<a  href="http://www.chedong.com/blog/archives/001249.html">本声明</a>。<br>
<a  href="http://www.chedong.com/tech/ant.html" class="permalink">http://www.chedong.com/tech/ant.html</a>
</span>
<hr>
<div class="entry-body">
<p>内容摘要：<br>
ant是一个基于JAVA的自动化脚本引擎，脚本格式为XML。除了做JAVA编译相关任务外，ANT还可以通过插件实现很多应用的调用。<br>
</p>
<ol>
    <li>ANT的基本概念：</li>
    <li>ANT的安装：解包，设置路径</li>
    <li>ANT的使用：最好的学习只不过是一个简单实用的例子起步&#8230;&#8230;</li>
</ol>
</div>
<h2>ANT的基本概念：Java的Makefile</h2>
<p>当一个代码项目大了以后，每次重新编译，打包，测试等都会变得非常复杂而且重复，因此c语言中有make脚本来帮助这些工作的批量完成。在Java
中应用是平台无关性的，当然不会用平台相关的make脚本来完成这些批处理任务了，ANT本身就是这样一个流程脚本引擎，用于自动化调用程序完成项目的编
译，打包，测试等。除了基于JAVA是平台无关的外，脚本的格式是基于XML的，比make脚本来说还要好维护一些。<br>
</p>
<p>每个ant脚本（缺省叫build.xml）中设置了一系列任务(target)：比如对于一个一般的项目可能需要有以下任务。</p>
<ul>
    <li> 任务1：usage 打印本脚本的帮助信息（缺省） </li>
    <li> 任务2：clean &lt;-- init 清空初始化环境 </li>
    <li> 任务3：javadoc &lt;-- build &lt;-- init 生成JAVADOC </li>
    <li> 任务4：jar &lt;-- build &lt;-- init 生成JAR </li>
    <li> 任务5：all &lt;-- jar + javadoc &lt;-- build &lt;-- init
    完成以上所有任务：jar javadoc </li>
</ul>
而多个任务之间往往又包含了一定了依赖关系：比如把整个应用打包任务(jar)的这个依赖于编译任务(build)，而编译任务又依赖于整个环境初始化任
务(init)等。<br>
<br>
注：我看到很多项目的ant脚本中的命名基本上都是一致的，比如：编译一般叫build或者compile；打包一般叫jar或war；生成文档一般命名
为javadoc或javadocs；执行全部任务all。在每个任务的中，ANT会根据配置调用一些外部应用并配以相应参数执行。虽然ANT可调用的外
部应用种类非常丰富，但其实最常用的就2，3个：比如javac
javadoc jar等。
<h2>ANT的安装</h2>
解包后在系统可执行路径中加入指向ant的bin的路径就可以了，比如可以在GNU/Linux上把以下配置加入/etc/profile中：<br>
export ANT_HOME=/home/ant<br>
export JAVA_HOME=/usr/java/j2sdk1.4.1<br>
export PATH=$PATH:$JAVA_HOME/bin:$ANT_HOME/bin<br>
<br>
这样执行ant
后，如果不指定配置文件ant会缺省找build.xml这个配置文件，并根据配置文件执行任务，缺省的任务设置可以指向最常用的任务，比如：
build，或指向打印帮助信息：usage，告诉用户有那些脚本选项可以使用。<br>
<br>
<h2>ANT的使用<br>
</h2>
<div style="text-align: left;">最好的学习过程就是看懂那些open
source项目中的build.xml脚本，然后根据自己的需要简化成一个更简单的，ANT和APACHE上很多非常工程派的项目：简单易用，而且适应
性非常强，因为这些项目的建立往往来源于开发人员日常最直接的需求。<br>
以下是的一个<a  href="http://sourceforge.net/projects/weblucene/">WebLucene</a>应
用的例子：修改自<a  href="http://www.jdom.org/">JDOM</a>的build.xml：<br>
<br>
&lt;project default="usage" basedir="."&gt;<br>
<br>
&nbsp; &lt;!--
===================================================================
--&gt;<br>
&nbsp; &lt;!-- Initialization
target&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
--&gt;<br>
&nbsp; &lt;!--
===================================================================
--&gt;<br>
&nbsp; &lt;target name="init"&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;tstamp/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;property file="${basedir}/build.properties" /&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;property name="Name" value="ProjectFullName"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;property name="name" value="project_name"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;property name="version" value="0.2"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;property name="year" value="2003"/&gt;<br>
<br>
&nbsp;&nbsp;&nbsp; &lt;echo message="----------- ${Name} ${version}
[${year}] ------------"/&gt;<br>
<br>
&nbsp;&nbsp;&nbsp; &lt;property name="debug" value="off"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;property name="optimize" value="on"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;property name="deprecation" value="on"/&gt;<br>
<br>
&nbsp;&nbsp;&nbsp; &lt;property name="src.dir"
value="./src/WEB-INF/src"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;property name="lib.dir"
value="./src/WEB-INF/lib"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;property name="packages"
value="com.chedong.*,org.apache.lucene.*"/&gt;<br>
<br>
&nbsp;&nbsp;&nbsp; &lt;property name="build.src"
value="./src/WEB-INF/build"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;property name="build.dest"
value="./src/WEB-INF/classes"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;property name="build.javadocs"
value="./src/doc"/&gt;<br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; &lt;path id="classpath"&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;pathelement
path="${jsdk_jar}"/&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;fileset
dir="${lib.dir}"&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;include name="**/*.jar"/&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/fileset&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;/path&gt;<br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; &lt;filter token="year" value="${year}"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;filter token="version" value="${version}"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;filter token="date" value="${TODAY}"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;filter token="log" value="true"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;filter token="verbose" value="true"/&gt;<br>
&nbsp; &lt;/target&gt;<br>
<br>
&nbsp; &lt;!--
===================================================================
--&gt;<br>
&nbsp; &lt;!-- Help on
usage&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
--&gt;<br>
&nbsp; &lt;!--
===================================================================
--&gt;<br>
&nbsp; &lt;target name="usage" depends="init"&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;echo message="${Name} Build file"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;echo
message="-------------------------------------------------------------"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;echo message=""/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;echo message=" available targets are:"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;echo message=""/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;echo message="&nbsp;&nbsp;
jar&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --&gt; generates the ${name}.jar
file"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;echo message="&nbsp;&nbsp;
build&nbsp;&nbsp;&nbsp; --&gt; compiles the source code"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;echo message="&nbsp;&nbsp; javadoc&nbsp; --&gt;
generates the API documentation"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;echo message="&nbsp;&nbsp;
clean&nbsp;&nbsp;&nbsp; --&gt; cleans up the directory"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;echo message=""/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;echo message=" Please rename
build.properties.default to build.properties"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;echo message=" and edit build.properties to
specify JSDK 2.3 classpath."/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;echo message=""/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;echo message=" See the comments inside the
build.xml file for more details."/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;echo
message="-------------------------------------------------------------"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;echo message=""/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;echo message=""/&gt;<br>
&nbsp; &lt;/target&gt;<br>
<br>
&nbsp; &lt;!--
===================================================================
--&gt;<br>
&nbsp; &lt;!-- Prepares the source
code&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
--&gt;<br>
&nbsp; &lt;!--
===================================================================
--&gt;<br>
&nbsp; &lt;target name="prepare-src" depends="init"&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;!-- create directories --&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;mkdir dir="${build.src}"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;mkdir dir="${build.dest}"/&gt;<br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; &lt;!-- copy src files --&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;copy todir="${build.src}"&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;fileset dir="${src.dir}"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;/copy&gt;<br>
&nbsp; &lt;/target&gt;<br>
<br>
&nbsp; &lt;!--
===================================================================
--&gt;<br>
&nbsp; &lt;!-- Compiles the source
directory&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
--&gt;<br>
&nbsp; &lt;!--
===================================================================
--&gt;<br>
&nbsp; &lt;target name="build" depends="prepare-src"&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;javac srcdir="${build.src}"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
destdir="${build.dest}"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
debug="${debug}"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
optimize="${optimize}"&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;classpath refid="classpath"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;/javac&gt;<br>
&nbsp; &lt;/target&gt;<br>
<br>
&nbsp; &lt;!--
===================================================================
--&gt;<br>
&nbsp; &lt;!-- Creates the class
package&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
--&gt;<br>
&nbsp; &lt;!--
===================================================================
--&gt;<br>
&nbsp; &lt;target name="jar" depends="build"&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;jar jarfile="${lib.dir}/${name}.jar"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; basedir="${build.dest}"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; includes="**"/&gt;<br>
&nbsp; &lt;/target&gt;<br>
<br>
&nbsp; &lt;!--
===================================================================
--&gt;<br>
&nbsp; &lt;!-- Creates the API
documentation&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
--&gt;<br>
&nbsp; &lt;!--
===================================================================
--&gt;<br>
&nbsp; &lt;target name="javadoc" depends="build"&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;mkdir dir="${build.javadocs}"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;javadoc packagenames="${packages}"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
sourcepath="${build.src}"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
destdir="${build.javadocs}"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
author="true"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
version="true"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
use="true"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
splitindex="true"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
windowtitle="${Name} API"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
doctitle="${Name}"&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;classpath refid="classpath"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;/javadoc&gt;<br>
&nbsp; &lt;/target&gt;<br>
<br>
&nbsp; &lt;!--
===================================================================
--&gt;<br>
&nbsp; &lt;!-- Clean
targets&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
--&gt;<br>
&nbsp; &lt;!--
===================================================================
--&gt;<br>
&nbsp; &lt;target name="clean" depends="init"&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;delete dir="${build.src}"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;delete dir="${build.dest}/org"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;delete dir="${build.dest}/com"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;delete&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;fileset dir="${build.dest}"
includes="**/*.class"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;/delete&gt;<br>
&nbsp; &lt;/target&gt;<br>
&lt;/project&gt;<br>
&lt;!-- End of file --&gt;<br>
<br>
缺省任务：usage 打印帮助文档，告诉有那些任务选项：可用的有build, jar, javadoc和clean.<br>
<br>
初始化环境变量：init<br>
所有任务都基于一些基本环境变量的设置初始化完成，是后续其他任务的基础，在环境初始化过程中，有2点比较可以方便设置：<br>
<br>
1 除了使用却缺省的property设置了JAVA源路径和输出路径外，引用了一个外部的build.properties文件中的设置，<br>
&lt;property file="${basedir}/build.properties" /&gt;<br>
这样大部分简单配置用户只要会看懂build.properties就可以了，毕竟XML比起key
value的属性文件还是要可读性差一些。用build.properties也可以方便其他用户从编译的细节中解放出来。<br>
<br>
2 CLASSPATH设置：使用了其中的：<br>
&nbsp;&nbsp;&nbsp; &lt;path id="classpath"&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;pathelement
path="${jsdk_jar}"/&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;fileset
dir="${lib.dir}"&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;include name="**/*.jar"/&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/fileset&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;/path&gt;<br>
则相当于设置了：CLASSPATH=/path/to/resin/lib/jsdk23.jar;
/path/to/project/lib/*.jar;<br>
<br>
文件复制：prepare-src<br>
创建临时SRC存放目录和输出目录。<br>
&nbsp; &lt;!--
===================================================================
--&gt;<br>
&nbsp; &lt;!-- Prepares the source
code&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
--&gt;<br>
&nbsp; &lt;!--
===================================================================
--&gt;<br>
&nbsp; &lt;target name="prepare-src" depends="init"&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;!-- create directories --&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;mkdir dir="${build.src}"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;mkdir dir="${build.dest}"/&gt;<br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; &lt;!-- copy src files --&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;copy todir="${build.src}"&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;fileset dir="${src.dir}"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;/copy&gt;<br>
&nbsp; &lt;/target&gt;<br>
<br>
编译任务：build<br>
编译时的CLASSPATH环境通过一下方式找到引用一个path对象<br>
&lt;classpath refid="classpath"/&gt;<br>
<br>
打包任务：jar<br>
对应用打包生成项目所写名的.jar文件<br>
&nbsp; &lt;!--
===================================================================
--&gt;<br>
&nbsp; &lt;!-- Creates the class
package&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
--&gt;<br>
&nbsp; &lt;!--
===================================================================
--&gt;<br>
&nbsp; &lt;target name="jar" depends="build"&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;jar jarfile="${lib.dir}/${name}.jar"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; basedir="${build.dest}"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; includes="**"/&gt;<br>
&nbsp; &lt;/target&gt;<br>
<br>
生成JAVADOC文档任务: javadoc<br>
&nbsp; &lt;!--
===================================================================
--&gt;<br>
&nbsp; &lt;!-- Creates the API
documentation&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
--&gt;<br>
&nbsp; &lt;!--
===================================================================
--&gt;<br>
&nbsp; &lt;target name="javadoc" depends="build"&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;mkdir dir="${build.javadocs}"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;javadoc packagenames="${packages}"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
sourcepath="${build.src}"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
destdir="${build.javadocs}"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
author="true"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
version="true"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
use="true"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
splitindex="true"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
windowtitle="${Name} API"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
doctitle="${Name}"&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;classpath refid="classpath"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;/javadoc&gt;<br>
&nbsp; &lt;/target&gt;<br>
<br>
清空临时编译文件：clean<br>
&nbsp; &lt;!--
===================================================================
--&gt;<br>
&nbsp; &lt;!-- Clean
targets&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
--&gt;<br>
&nbsp; &lt;!--
===================================================================
--&gt;<br>
&nbsp; &lt;target name="clean" depends="init"&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;delete dir="${build.src}"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;delete dir="${build.dest}/org"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;delete dir="${build.dest}/com"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;delete&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;fileset dir="${build.dest}"
includes="**/*.class"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;/delete&gt;<br>
&nbsp; &lt;/target&gt;<br>
<br>
TODO：<br>
更多任务/扩展：（样例）<br>
</div>
<ul>
    <li> 测试任务：JUnit测试</li>
    <li> 代码风格检查任务：CheckStyle，Jalopy等</li>
    <li> 邮件警报任务：可以把以上这些任务的输出警告发送到制定的用户列表中，这个任务可以设置每天自动运行。</li>
</ul>
<br>
参考资料：<br>
Jakarta ANT:<br>
<a  href="http://ant.apache.org/">http://ant.apache.org</a><img src ="http://www.blogjava.net/kuxiaoku/aggbug/123385.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kuxiaoku/" target="_blank">苦笑枯</a> 2007-06-11 14:44 <a href="http://www.blogjava.net/kuxiaoku/archive/2007/06/11/123385.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java事件处理模式</title><link>http://www.blogjava.net/kuxiaoku/archive/2007/04/15/110830.html</link><dc:creator>苦笑枯</dc:creator><author>苦笑枯</author><pubDate>Sun, 15 Apr 2007 15:05:00 GMT</pubDate><guid>http://www.blogjava.net/kuxiaoku/archive/2007/04/15/110830.html</guid><wfw:comment>http://www.blogjava.net/kuxiaoku/comments/110830.html</wfw:comment><comments>http://www.blogjava.net/kuxiaoku/archive/2007/04/15/110830.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/kuxiaoku/comments/commentRss/110830.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kuxiaoku/services/trackbacks/110830.html</trackback:ping><description><![CDATA[<p>author：板桥里人</p>
<p>出处：JDON.COM</p>
<p>Java的事件模式是动态响应系统重要的基础，在图形界面领域的事件模式已经有很多文章介绍，但是在服务器端我们会碰到更多的事件模式，这里本人试图总结一下： </p>
<p>　　<strong>事件直接驱动模式</strong><br><br>　　事件模式的第一个要求就是性能的要求，需要直接而且快，Command模式是必须经常使用的，主要适合于迅速处理 前台的命令，Command模式往往是系统架构的重要部分，也是流程控制的主要模式。 </p>
<p>　　Command模式经常Java的Reflect一起使用，因为系统的事件处理系统是处于动态变化的，随着功能要求扩展，就可能有动态变化事件
处理响应系统，以Struts中action为例，我们知道，Structs的一个主要配置文件是struts-config.xml 如下： </p>
<table bgcolor="#ffffff" border="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>＜struts-config＞<br>　　＜action-mappings＞<br>　　　　＜action path="/login" type="com.javapro.struts.LoginAction"/＞<br>　　　　＜action path="/logout" type="com.javapro.struts.LogoutAction"/＞<br>　　＜/action-mappings＞<br>＜/struts-config＞ </td>
        </tr>
    </tbody>
</table>
<p>　　它实际是个command和event的映射关系，通过这个配置文件，运行时动态装载相应的Action，完成Command模式， 我们检查LoginAction代码，就可以看出Command模式的基本特征： </p>
<table bgcolor="#ffffff" border="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>public final class LoginAction extends Action { <br>　　public ActionForward execute(ActionMapping mapping, <br>　　　　ActionForm form, HttpServletRequest request, HttpServletResponse response) <br>　　　　throws Exception { <br>　　　　　　　　................. <br>　　} <br>} </td>
        </tr>
    </tbody>
</table>
<p>　　很明显，典型的Command模式需要有一个接口.接口中有一个统一的方法，这里统一的方法就是execute; </p>
<p>　　比如我们有个实时系统，客户段向服务器发出不同编码代号，意味着不同的请求，不同的请求有不同的Handler进行 处理，Handler接口是: </p>
<table bgcolor="#ffffff" border="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>
            <p>public class Handler{ </p>
            <p>　　public byte[] handleRequest(); </p>
            <p>} </p>
            </td>
        </tr>
    </tbody>
</table>
<p>　　不同性质的处理过程继承这个Handler接口，如负责进入系统的处理过程 </p>
<table bgcolor="#ffffff" border="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>
            <p>public class EnterHandler implements Handler{ </p>
            <p>　　public byte[] handleRequest(){ <br>　　//具体业务处理 <br>　　...... <br>　　} </p>
            <p>} </p>
            </td>
        </tr>
    </tbody>
</table>
<p>　　调用Handler时是: </p>
<table bgcolor="#ffffff" border="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>//从cache中获取这个requestId对应的Handler <br>Handler handler = (Handler)cache.get(new Integer(reqId)); <br>//调用handler的统一方法handleRequest() <br>byte[] outInf = handler.handleRequest(); </td>
        </tr>
    </tbody>
</table>
<p>　　以上是常用的一个事件驱动模式。它的特点是靠一个事件直接启动对应的事件处理器。 </p>
<p>　　Chain of
Responsibility职责链模式也应该属于这类，当事件到达后，让这个事件在我们提供的一批处理器中逐个挑选适合的处理器进行处理，这个模式缺点
是显然的，性能丧失在逐个挑选 上，一般不推荐使用，这个模式适合在我们无法预知发生的事件内容时使用，因为不知道发生事件的具体情况，
我们就无法在程序运行前事先为其指派相应的处理器，只能靠运行时，事件自己去摸索&#8220;撞运气&#8221;。 <br></p>
<br>
<p><span class="txt"><strong>监控式事件模式</strong><br><br>　　监控式事件模式就不同于事件直接驱动模式，它是借助第三者来监控和触发事件，这类事件的特点是： 有一个观察者置身事外在定期独立运行着，我们将我们要监听的事件向这个观察者注册，这样观察者就 代替我们来监听这个事件，应用客户端通过观察者来获得事件状况。
<p>　　应用客户端有三种与观察者交互的方式：1.直接融合 2.推方式 3.拉方式。 </p>
<p>　　直接融合就是说应用客户端自己就是观察者，两者融合，这样无疑应用客户端获得的触发时间是最快的。 </p>
<p>　　推方式就是观察者一旦侦测到事件发生，立即将事件Push推到应用客户端；拉方式类似收取邮件，应用客户端在需要时才从观察者拉取事件。 </p>
<p>　　JDK 1.4的None Blocking I/O是监控式事件模式的典型实现，Selector显然是一个监控I/O的第三者，当有外部事件进来，通过 调用Slector.select方法可以获得外部事件，从而进行处理，可参考我的本栏文章。 </p>
<p>　　监控式事件模式适合使用在触发性质的场合，比如数据库后端触发器 界面触发 I/O触发 状态改变触发等。 </p>
<p>　　我们以一个信件触发为例，这其实是个Observer应用例子: </p>
<p>　　比如用户提请服务器计算一个数据，如果用户同时要求将计算结果向自己信箱发一封，那么我们看如何设计？按照通常思维，这是一个次序问题，先在内
存中计算数据，然后将结果发送到他的信箱，最后返回结果到用户端，我们知道信件的发送是耗时的，因此，有可能网络的原因造成信件发送很慢，这是用户就一直
等不到他的计算结果，很显然，我们使用监控式事件模式来解决，让发信的事件由监控者去完成，只要需要时触发就可以了： </p>
<table bgcolor="#ffffff" border="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>
            <p>public class Computer extends Observable{ </p>
            <p>　　public Computer(){ <br>　　　　//将sendMailObserver设定为本类的观察者。 <br>　　　　addObserver(new sendMailObserver()); <br>　　} </p>
            <p>　　....... </p>
            <p><br>　　public void compute(String input,boolean needEmail,String email){ </p>
            <p>　　　　//计算操作 <br>　　　　......... </p>
            <p>　　　　if (needEmail){ </p>
            <p>　　　　　　//设置变化点 <br>　　　　　　 setChanged(); <br>　　　　　　//如果需要发送email，我们把email地址作为参数传送过去 <br>　　　　　　 notifyObservers(email); </p>
            <p>　　　　}　　　 <br>　　} </p>
            <p>｝</p>
            </td>
        </tr>
    </tbody>
</table>
<p>　　我们再来看监控观察者代码是如何写的？ </p>
<table bgcolor="#ffffff" border="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>
            <p>public class sendMailObserver implements Observer{ </p>
            <p>　　public void update(Observable obj,Object email){ </p>
            <p>　　　　if (email instanceof String){ </p>
            <p>　　　　　　sendMail(email); </p>
            <p>　　　　} </p>
            <p>　　} </p>
            <p>} <br></p>
            </td>
        </tr>
    </tbody>
</table>
<p>　　这样服务器在执行compute方法时，就没有发送邮件的等待，一直接继续执行。 <br><br>　　监控式事件模式和事件直接驱动模式可以在一个系统一起使用，外界信号通过事件直接驱动模式启动系统处理模块， 系统处理模块处理过程中，可以通过监控式事件模式来触发其它后台任务。这样一个架构非常适合实时处理系统。 </p>
<p>　　既然事件处理模式是众多应用系统的基本模式，那么应该可以形成一个框架标准，JMX的notification Model就是这样一个架构设计。 </p>
<p>　　<strong>JMX Notification Model</strong><br><br>　　我们知道，JMX是提供了一种对MBean资源执行控制和配
置的管理机制，但这只是复杂的，分布式的系统中的一部分， 还有需要资源能够感应状态改变或者特定事件变化的机制，这就是JMX
Notification Model。 在JMX Notification
Model中均可以实现"事件直接驱动模式"和"监控式事件模式"，这取决于你的应用需求。 </p>
<p>　　JMX Notification
Model允许MBean通过调用notifications广播事件，接受者只要注册为一个listerner， JMX的 MBean
notification model 将会激活这个listerner注册一次，然后将一直接受到 来自广播者发出的各种事件。 </p>
<p>　　事件模式有三个角色，第一个是事件发出者producer 然后是事件接受者Consumer,第三个 是要传输的事件。JMX notification model也是这样分别依靠下列组件来实现这三个角色： </p>
<p>　　A. NotificationBroadcaster接口, 事件广播发出者， 这个接口允许监听者在需要发出的notification中注册他们感兴趣的事件。 <br><br>　　B. 通用事件(Notification)，这是我们要传输的事件。 Notification事件能被直接使用，也能成为子类，这些都依赖于随同事件传输的信息。 通过使用通用事件类型，监听者将能接受来自广播者所有类型的事件。 <br>　　<br>　　C. NotificationListener接口, 事件监听者或者接受者， 用于接受来自广播者的任何notification信号。 <br><br>　　D. NotificationFilter接口, 这个接口为notification的监听者提供一个对发出事件的过滤器。 <br><br>　　E. NotificationEmitter 接口, 扩展了NotificationBroadcaster接口，当删除监听者时允许更多的控制功能。 </p>
<p>　　只要是MBean，就既可以成为notification的发布广播者，也可以成为notification的监听者接受者，或者同时两者都可以。 </p>
<p>　　Attribute Change Notifications <br><br>　　Attribute Change Notifications是一种特殊的notification, 任何时候MBean属性attribute 被修改，外界能够被通知到。 </p>
<p>　　在JMX架构中，MBean能够在属性attribute变化发生时，发出通知，关于诊断属性变化的机制以及触发 通知事件并不属于JMX规定部分，每个MBean可以有自己独立的实现方式。 </p>
<p>　　Timer Service <br><br>　　Timer Service触发器是在规定的日期和事件发出通知，它能够一一个恒定的间隙不断重复发出通知， 通知可以发往所有注册为接受timer通知的对象，Timer Service也是一个可管理的MBean，允许应用系统设置 一个可配置的调度程度。 </p>
<p>　　Monitoring <br><br>　　通过使用monitoring
service，一个或多个MBean属性将按规定间隔时间被监视，
对于被观察的Mbean,监视器monitor将从它上面获得一个值，叫derived gauge，这个derived gauge可以是
被观察属性的原值，也可以是一个数字性属性连续被观察值之差。 </p>
<p>　　当derived gauge值满足一系列条件时，每个monitor server将会发出一个特定类型的通知。 这些条件都是在monitor被初始化时设定的，也可以通过monitor MBean的管理接口动态设定。 </p>
<p>　　根据MBean内部属性值类型有三种monitor: </p>
<p>　　A.CounterMonitor - 使用Java的整数类型来观察属性，有一个行为特征： <br><br>　　　a. 总是大于或等于零. <br><br>　　　b. 能自增. <br><br>　　　c. 能回滚. </p>
<p>　　B.GaugeMonitor - 使用java的整数或浮点类型观察属性。象gauge(测量仪器) 要么上升　要么下降减少。 </p>
<p>　　C StringMonitor - 使用String类型观察属性. </p>
<p>　　<strong>事件处理架构</strong><br><br>　　JMS是基于Socket的一种消息处理框架，原理类似于监控式事件模式，但是JMS已经把这种模式上升到架构的高度。不同JVM间也依靠JMS消息可以实现事件系统（注意是系统，不简单是一个小事件了）的触发和激活。 </p>
<p>　　<img src="http://www.yesky.com/20030303/jt-030303-jmsarchitecture.jpg" height="349" width="599"><br><br>　　从上面JMS的架构图可以看出事件三个角色Producer和Consumer以及事件信息本身Message．JMS就是在Producer和Consumer之间建立一个连接Connection． </p>
<p>　　JMS可实现同步或异步的事件触发机制，分别是通过Poin to
Point(拉方式)和Pubilsh/Subscibe(推方式)具体完成，在分布式计算环境中，异步机制是非常重要，可以起到解耦作用，因为分布环境
中单点错误或通讯问题是经常发生的，整个分布式系统不能总是依靠同步机制来可靠地传递事件或notification． </p>
<p>　　由此可见，事件处理模式从Java诸多架构到我们具体应用程序，随处可见，根据不同的应用需求选择不同的事件处理模式，才能真正挖掘Java的潜在性能。 </p>
</span></p><img src ="http://www.blogjava.net/kuxiaoku/aggbug/110830.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kuxiaoku/" target="_blank">苦笑枯</a> 2007-04-15 23:05 <a href="http://www.blogjava.net/kuxiaoku/archive/2007/04/15/110830.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>拼包函数及网络封包的异常处理</title><link>http://www.blogjava.net/kuxiaoku/archive/2007/04/07/109154.html</link><dc:creator>苦笑枯</dc:creator><author>苦笑枯</author><pubDate>Sat, 07 Apr 2007 14:07:00 GMT</pubDate><guid>http://www.blogjava.net/kuxiaoku/archive/2007/04/07/109154.html</guid><wfw:comment>http://www.blogjava.net/kuxiaoku/comments/109154.html</wfw:comment><comments>http://www.blogjava.net/kuxiaoku/archive/2007/04/07/109154.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kuxiaoku/comments/commentRss/109154.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kuxiaoku/services/trackbacks/109154.html</trackback:ping><description><![CDATA[<p>本文作者：sodme<br>本文出处：<a  href="http://blog.csdn.net/sodme">http://blog.csdn.net/sodme</a><br>声明：本文可以不经作者同意任意转载、复制、传播，但任何对本文的引用都请保留作者、出处及本声明信息。谢谢！<br><br>
常见的网络服务器，基本上是7*24小时运转的，对于网游来说，至少要求服务器要能连续工作一周以上的时间并保证不出现服务器崩溃这样的灾难性事件。事
实上，要求一个服务器在连续的满负荷运转下不出任何异常，要求它设计的近乎完美，这几乎是不太现实的。服务器本身可以出异常（但要尽可能少得出），但是，
服务器本身应该被设计得足以健壮，&#8220;小病小灾&#8221;打不垮它，这就要求服务器在异常处理方面要下很多功夫。</p>
<p>　　服务器的异常处理包括的内容非常广泛，本文仅就在网络封包方面出现的异常作一讨论，希望能对正从事相关工作的朋友有所帮助。</p>
<p>
关于网络封包方面的异常，总体来说，可以分为两大类：一是封包格式出现异常；二是封包内容（即封包数据）出现异常。在封包格式的异常处理方面，我们在最
底端的网络数据包接收模块便可以加以处理。而对于封包数据内容出现的异常，只有依靠游戏本身的逻辑去加以判定和检验。游戏逻辑方面的异常处理，是随每个游
戏的不同而不同的，所以，本文随后的内容将重点阐述在网络数据包接收模块中的异常处理。</p>
<p>　　为方便以下的讨论，先明确两个概念（这两个概念是为了叙述方面，笔者自行取的，并无标准可言）：<br>　　1、逻辑包：指的是在应用层提交的数据包，一个完整的逻辑包可以表示一个确切的逻辑意义。比如登录包，它里面就可以含有用户名字段和密码字段。尽管它看上去也是一段缓冲区数据，但这个缓冲区里的各个区间是代表一定的逻辑意义的。<br>　　2、物理包：指的是使用recv(recvfrom)或wsarecv(wsarecvfrom)从网络底层接收到的数据包，这样收到的一个数据包，能不能表示一个完整的逻辑意义，要取决于它是通过UDP类的&#8220;数据报协议&#8221;发的包还是通过TCP类的&#8220;流协议&#8221;发的包。</p>
<p>
我们知道，TCP是流协议，&#8220;流协议&#8221;与&#8220;数据报协议&#8221;的不同点在于：&#8220;数据报协议&#8221;中的一个网络包本身就是一个完整的逻辑包，也就是说，在应用层使用
sendto发送了一个逻辑包之后，在接收端通过recvfrom接收到的就是刚才使用sendto发送的那个逻辑包，这个包不会被分开发送，也不会与其
它的包放在一起发送。但对于TCP而言，TCP会根据网络状况和neagle算法，或者将一个逻辑包单独发送，或者将一个逻辑包分成若干次发送，或者会将
若干个逻辑包合在一起发送出去。正因为TCP在逻辑包处理方面的这种粘合性，要求我们在作基于TCP的应用时，一般都要编写相应的拼包、解包代码。</p>
<p>　　因此，基于TCP的上层应用，一般都要定义自己的包格式。TCP的封包定义中，除了具体的数据内容所代表的逻辑意义之外，第一步就是要确定以何种方式表示当前包的开始和结束。通常情况下，表示一个TCP逻辑包的开始和结束有两种方式：<br>　　1、以特殊的开始和结束标志表示，比如FF00表示开始，00FF表示结束。<br>　　2、直接以包长度来表示。比如可以用第一个字节表示包总长度，如果觉得这样的话包比较小，也可以用两个字节表示包长度。</p>
<p>　　下面将要给出的代码是以第2种方式定义的数据包，包长度以每个封包的前两个字节表示。我将结合着代码给出相关的解释和说明。</p>
<p>　　函数中用到的变量说明：</p>
<p>　　CLIENT_BUFFER_SIZE：缓冲区的长度，定义为：Const int CLIENT_BUFFER_SIZE=4096。<br>　　m_ClientDataBuf：数据整理缓冲区，每次收到的数据，都会先被复制到这个缓冲区的末尾，然后由下面的整理函数对这个缓冲区进行整理。它的定义是：char m_ClientDataBuf[2* CLIENT_BUFFER_SIZE]。<br>　　m_DataBufByteCount：数据整理缓冲区中当前剩余的未整理字节数。<br>　　GetPacketLen(const char*)：函数，可以根据传入的缓冲区首址按照应用层协议取出当前逻辑包的长度。<br>　　GetGamePacket(const char*, int)：函数，可以根据传入的缓冲区生成相应的游戏逻辑数据包。<br>　　AddToExeList(PBaseGamePacket)：函数，将指定的游戏逻辑数据包加入待处理的游戏逻辑数据包队列中，等待逻辑处理线程对其进行处理。<br>　　DATA_POS：指的是除了包长度、包类型等这些标志型字段之外，真正的数据包内容的起始位置。</p>
<p>Bool SplitFun(const char* pData,const int &amp;len)<br>{<br>&nbsp;&nbsp;&nbsp; PBaseGamePacket pGamePacket=NULL;<br>&nbsp;&nbsp;&nbsp; __int64 startPos=0, prePos=0, i=0;<br>&nbsp;&nbsp;&nbsp; int packetLen=0;</p>
<p>&nbsp;　//先将本次收到的数据复制到整理缓冲区尾部<br>&nbsp;&nbsp;&nbsp; startPos = m_DataBufByteCount;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp; memcpy( m_ClientDataBuf+startPos, pData, len );<br>&nbsp;&nbsp;&nbsp; m_DataBufByteCount += len;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp; //当整理缓冲区内的字节数少于DATA_POS字节时，取不到长度信息则退出<br>　//注意：退出时并不置m_DataBufByteCount为0<br>&nbsp;&nbsp;&nbsp; if (m_DataBufByteCount &lt; DATA_POS+1)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; //根据正常逻辑，下面的情况不可能出现，为稳妥起见，还是加上<br>&nbsp;&nbsp;&nbsp; if (m_DataBufByteCount &gt;&nbsp; 2*CLIENT_BUFFER_SIZE)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //设置m_DataBufByteCount为0，意味着丢弃缓冲区中的现有数据<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_DataBufByteCount = 0;</p>
<p>　　//可以考虑开放错误格式数据包的处理接口，处理逻辑交给上层<br>　　//OnPacketError()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;<br>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; //还原起始指针<br>&nbsp; &nbsp;&nbsp; startPos = 0;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; //只有当m_ClientDataBuf中的字节个数大于最小包长度时才能执行此语句<br>&nbsp;&nbsp;&nbsp; packetLen = GetPacketLen( pIOCPClient-&gt;m_ClientDataBuf );</p>
<p>&nbsp;&nbsp;&nbsp; //当逻辑层的包长度不合法时，则直接丢弃该包<br>&nbsp;&nbsp;&nbsp; if ((packetLen &lt; DATA_POS+1) || (packetLen &gt; 2*CLIENT_BUFFER_SIZE))<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_DataBufByteCount = 0;</p>
<p>　　//OnPacketError()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;<br>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; //保留整理缓冲区的末尾指针<br>&nbsp;&nbsp;&nbsp; __int64 oldlen = m_DataBufByteCount;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; while ((packetLen &lt;= m_DataBufByteCount) &amp;&amp; (m_DataBufByteCount&gt;0))<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //调用拼包逻辑，获取该缓冲区数据对应的数据包<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pGamePacket = GetGamePacket(m_ClientDataBuf+startPos, packetLen);&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (pGamePacket!=NULL)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //将数据包加入执行队列<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AddToExeList(pGamePacket);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pGamePacket = NULL;<br>&nbsp;<br>　　//整理缓冲区的剩余字节数和新逻辑包的起始位置进行调整<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_DataBufByteCount -= packetLen;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; startPos += packetLen;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //残留缓冲区的字节数少于一个正常包大小时，只向前复制该包随后退出<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (m_DataBufByteCount &lt; DATA_POS+1)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(i=startPos; i&lt;startPos+m_DataBufByteCount; ++i)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_ClientDataBuf[i-startPos] = m_ClientDataBuf[i];</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;packetLen = GetPacketLen(m_ClientDataBuf + startPos );</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //当逻辑层的包长度不合法时，丢弃该包及缓冲区以后的包<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((packetLen&lt;DATA_POS+1) || (packetLen&gt;2*CLIENT_BUFFER_SIZE))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_DataBufByteCount = 0;</p>
<p>&nbsp;&nbsp;&nbsp; 　　//OnPacketError()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (startPos+packetLen&gt;=oldlen)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(i=startPos; i&lt;startPos+m_DataBufByteCount; ++i)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_ClientDataBuf[i-startPos] = m_ClientDataBuf[i];&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp; }//取所有完整的包</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; return true;<br>}<br><br>　　以上便是数据接收模块的处理函数，下面是几点简要说明：</p>
<p>　　1、用于拼包整理的缓冲区(m_ClientDataBuf)应该比recv中指定的接收缓冲区(pData)长度(CLIENT_BUFFER_SIZE)要大，通常前者是后者的2倍(2*CLIENT_BUFFER_SIZE)或更大。<br><br>　　2、为避免因为剩余数据前移而导致的额外开销，建议m_ClientDataBuf使用环形缓冲区实现。<br><br>
3、为了避免出现无法拼装的包，我们约定每次发送的逻辑包，其单个逻辑包最大长度不可以超过CLIENT_BUFFER_SIZE的2倍。因为我们的整
理缓冲区只有2*CLIENT_BUFFER_SIZE这么长，更长的数据，我们将无法整理。这就要求在协议的设计上以及最终的发送函数的处理上要加上这
样的异常处理机制。</p>
<p><br>　　4、对于数据包过短或过长的包，我们通常的情况是置m_DataBufByteCount为0，即舍弃当前
包的处理。如果此处不设置m_DataBufByteCount为0也可，但该客户端只要发了一次格式错误的包，则其后继发过来的包则也将连带着产生格式
错误，如果设置m_DataBufByteCount为0，则可以比较好的避免后继的包受此包的格式错误影响。更好的作法是，在此处开放一个封包格式异常
的处理接口(OnPacketError)，由上层逻辑决定对这种异常如何处置。比如上层逻辑可以对封包格式方面出现的异常进行计数，如果错误的次数超过
一定的值，则可以断开该客户端的连接。</p>
5、建议不要在recv或wsarecv的函数后，就紧接着作以上的处理。当recv收到一段数
据后，生成一个结构体或对象(它主要含有data和len两个内容，前者是数据缓冲区，后者是数据长度)，将这样的一个结构体或对象放到一个队列中由后面
的线程对其使用SplitFun函数进行整理。这样，可以最大限度地提高网络数据的接收速度，不至因为数据整理的原因而在此处浪费时间。<img src ="http://www.blogjava.net/kuxiaoku/aggbug/109154.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kuxiaoku/" target="_blank">苦笑枯</a> 2007-04-07 22:07 <a href="http://www.blogjava.net/kuxiaoku/archive/2007/04/07/109154.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>心情日志</title><link>http://www.blogjava.net/kuxiaoku/archive/2007/04/01/107765.html</link><dc:creator>苦笑枯</dc:creator><author>苦笑枯</author><pubDate>Sun, 01 Apr 2007 07:44:00 GMT</pubDate><guid>http://www.blogjava.net/kuxiaoku/archive/2007/04/01/107765.html</guid><wfw:comment>http://www.blogjava.net/kuxiaoku/comments/107765.html</wfw:comment><comments>http://www.blogjava.net/kuxiaoku/archive/2007/04/01/107765.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kuxiaoku/comments/commentRss/107765.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kuxiaoku/services/trackbacks/107765.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 今天等明天，明天等后天。。。。终于到了我不得不面对的时候了。抓紧时间吧<br> <img src ="http://www.blogjava.net/kuxiaoku/aggbug/107765.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kuxiaoku/" target="_blank">苦笑枯</a> 2007-04-01 15:44 <a href="http://www.blogjava.net/kuxiaoku/archive/2007/04/01/107765.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[分享]JDOM1.0的API文档（CHM版）</title><link>http://www.blogjava.net/kuxiaoku/archive/2007/03/27/106798.html</link><dc:creator>苦笑枯</dc:creator><author>苦笑枯</author><pubDate>Tue, 27 Mar 2007 15:18:00 GMT</pubDate><guid>http://www.blogjava.net/kuxiaoku/archive/2007/03/27/106798.html</guid><wfw:comment>http://www.blogjava.net/kuxiaoku/comments/106798.html</wfw:comment><comments>http://www.blogjava.net/kuxiaoku/archive/2007/03/27/106798.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/kuxiaoku/comments/commentRss/106798.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kuxiaoku/services/trackbacks/106798.html</trackback:ping><description><![CDATA[JDOM1.0 API 的文档<br><a href="http://www.blogjava.net/Files/kuxiaoku/JDOMAPIDOCS.rar">http://www.blogjava.net/Files/kuxiaoku/JDOMAPIDOCS.rar</a><br><br>点击下载<br> <img src ="http://www.blogjava.net/kuxiaoku/aggbug/106798.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kuxiaoku/" target="_blank">苦笑枯</a> 2007-03-27 23:18 <a href="http://www.blogjava.net/kuxiaoku/archive/2007/03/27/106798.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[分享]Java设计模式资料</title><link>http://www.blogjava.net/kuxiaoku/archive/2007/03/27/106792.html</link><dc:creator>苦笑枯</dc:creator><author>苦笑枯</author><pubDate>Tue, 27 Mar 2007 15:07:00 GMT</pubDate><guid>http://www.blogjava.net/kuxiaoku/archive/2007/03/27/106792.html</guid><wfw:comment>http://www.blogjava.net/kuxiaoku/comments/106792.html</wfw:comment><comments>http://www.blogjava.net/kuxiaoku/archive/2007/03/27/106792.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kuxiaoku/comments/commentRss/106792.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kuxiaoku/services/trackbacks/106792.html</trackback:ping><description><![CDATA[	在网上闲逛时看到一个网站上登的关于设计模式的资料，觉得不错就down下来做成电子书保存。<br>现上传上来大家一起分享。<br><br><a href="http://www.blogjava.net/Files/kuxiaoku/DESIGN.rar">http://www.blogjava.net/Files/kuxiaoku/DESIGN.rar</a><br><br>点击即可下载。 <img src ="http://www.blogjava.net/kuxiaoku/aggbug/106792.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kuxiaoku/" target="_blank">苦笑枯</a> 2007-03-27 23:07 <a href="http://www.blogjava.net/kuxiaoku/archive/2007/03/27/106792.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>