ant资料一

编译源代码
由于 Ant 的主要目标是生成 Java 应用程序,它能够内在地、出色地支持调用 javac 编译器以及其他

Java 相关任务就毫不奇怪了。下面是编译 Java 代码的任务的编写方式:
<javac srcdir="src"/>
这个标签寻找 src 目录中以 .java 为扩展名的所有文件,并对它们调用 javac 编译器,从而在相同的

目录中生成类文件。当然,将类文件放在一个单独的目录结构中通常会更清晰;可以通过添加 destdir

属性来让 Ant 做到这点。其他有用的属性包括:

classpath:等价于 javac 的 -classpath 选项。
debug="true":指示编译器应该带调试信息编译源文件。
javac 任务的一个重要特点在于,它仅编译那些它认为需要编译的源文件。如果某个类文件已经存在,

并且对应的源文件自从该类文件生成以来还没有改变过,那么该源文件就不会被重新编译。javac 任务

的输出显示了实际被编译的源文件的数目。编写一个 clean 目标来从目标目录移除生成的任何类文件是

个很好的习惯。如果想要确保所有源文件都已编译,就可以使用这个任务。这种行为刻画了 Ant 的许多

任务的特点:如果某个任务能够确定所请求的操作不需要执行,那么该操作就会被跳过。

像 Ant 一样,javac 编译器本身也是用 Java 语言实现的。这对 Ant 中的 javac 任务的使用来说非常

有利,因为它通常调用 Ant 运行所在的相同 Java 虚拟机(JVM)中的编译器类。在每次需要编译 Java

代码时,其他生成工具通常需要运行一个新的 javac 进程,从而需要一个新的 JVM 实例。但是在使用

Ant 的情况下,只需要单个 JVM 实例,它既用于运行 Ant 本身,也用于执行所有必需的编译任务(以

及其他相关任务,比如处理 JAR 文件)。这是一种高效得多的资源使用方式,能够极大地缩短项目生成

时间。

 

编译器选项

正如我们从前一小节看到的,Ant 的 javac 任务的默认行为是调用运行 Ant 本身的任何 JVM 的标准编

译器。然而,有时您可能想要单独地调用编译器 ―― 例如当你希望指定编译器的某些内存选项,或者

需要使用一种不同级别的编译器的时候。为实现这个目的,只需将 javac 的 fork 属性设置为 true,

比如像下面这样:


<javac srcdir="src" fork="true"/>


如果想要指定一个不同的 javac 可执行文件,并向它传递一个最大内存设置,您可以像下面这样做:


<javac srcdir="src" fork="true" executable="d:/sdk141/bin/javac"
memoryMaximumSize="128m"/>


甚至可以将 Ant 配置为使用某种不同的编译器。受支持的编译器包括开放源代码的 Jikes 编译器和来

自 GNU 编译器集(GNU Compiler Collection,GCC)的 GCI 编译器。(请参阅参考资料以了解关于这

两种编译器的更多信息。)可以通过两种方式指定这些编译器:可以设置 build.compiler 属性,这将

应用于使用 javac 任务的所有场合;或根据需要设置每个javac 任务中的 compiler 属性。

javac 任务还支持其他许多选项。请参考 Ant 手册以了解更多细节(请参阅参考资料)。

创建JAR文件

 
创建 JAR 文件 第 4 页(共6 页)

 


在编译 Java 源文件之后,结果类文件通常被打包到一个 JAR 文件中,这个文件类似 zip 归档文件。

每个 JAR 文件都包含一个清单文件,它可以指定该 JAR 文件的属性。

下面是 Ant 中 jar 任务的一个简单使用例子:


<jar destfile="package.jar" basedir="classes"/>


这将创建一个名为 package.jar 的 JAR 文件,并把 classes 目录中的所有文件添加到其中(JAR 文件

能够包含任意类型的文件,而不只是类文件)。此处没有指定清单文件,因此 Ant 将提供一个基本的清

单文件。

manifest 属性允许指定一个用作该 JAR 文件的清单的文件。清单文件的内容还可以使用 manifest 任

务在生成文件中指定。这个任务能够像文件系统写入一个清单文件,或者能够实际嵌套在 jar 之内,以

便一次性地创建清单文件和 JAR 文件。 例如:


<jar destfile="package.jar" basedir="classes">
  <manifest>
    <attribute name="Built-By" value="${user.name}"/>
    <attribute name="Main-class" value="package.Main"/>
  </manifest>
</jar>

 生成时间戳


在生成环境中使用当前时间和日期,以某种方式标记某个生成任务的输出,以便记录它是何时生成的,

这经常是可取的。这可能涉及编辑一个文件,以便插入一个字符串来指定日期和时间,或将这个信息合

并到 JAR 或 zip 文件的文件名中。

这种需要是通过简单但是非常有用的 tstamp 任务来解决的。这个任务通常在某次生成过程开始时调用

,比如在一个 init 目标中。这个任务不需要属性,许多情况下只需 <tstamp/> 就足够了。

tstamp 不产生任何输出;相反,它根据当前系统时间和日期设置 Ant 属性。下面是 tstamp 设置的一

些属性、对每个属性的说明,以及这些属性可被设置到的值的例子:

属性  说明  例子 
DSTAMP  设置为当前日期,默认格式为yyyymmdd  20031217
TSTAMP  设置为当前时间,默认格式为 hhmm  1603
TODAY  设置为当前日期,带完整的月份 2003 年 12 月 17 日

例如,在前一小节中,我们按如下方式创建了一个 JAR 文件:


<jar destfile="package.jar" basedir="classes"/>


在调用 tstamp 任务之后,我们能够根据日期命名该 JAR 文件,如下所示:


<jar destfile="package-${DSTAMP}.jar" basedir="classes"/>


因此,如果这个任务在 2003 年 12 月 17 日调用,该 JAR 文件将被命名为 package-20031217.jar。

还可以配置 tstamp 任务来设置不同的属性,应用一个当前时间之前或之后的时间偏移,或以不同的方

式格式化该字符串。所有这些都是使用一个嵌套的 format 元素来完成的,如下所示:


<tstamp>
   <format property="OFFSET_TIME"
           pattern="HH:mm:ss"
           offset="10" unit="minute"/>
</tstamp>


上面的清单将 OFFSET_TIME 属性设置为距离当前时间 10 分钟之后的小时数、分钟数和秒数。

用于定义格式字符串的字符与 java.text.SimpleDateFormat 类所定义的那些格式字符相同。


综合

前面几小节为我们提供了生成简单 Java 项目所需的足够知识。下面将把这些代码片断组合成一个完整

的生成文件,它将编译 src 目录下的所有源代码,将结果类文件放在 build 目录下,然后把所有类文

件打包到 dist 目录中的一个 JAR 文件中。要自己试验这个生成文件,您所需要的就是包含一个或多个

Java 源代码文件的 src 目录 ―― 这个目录可以包含从简单的“Hell World”程序到来自某个现有项

目的大量源文件的任何内容。如果需要向 Java classpath 添加 JAR 文件或其他任何内容,以便成功地

编译源代码,您只需在 javac 任务中为其添加一个 classpath 属性。

该生成文件看起来如下:


<?xml version="1.0"?>
<project default="dist" name="Project Argon">
     <description>A simple Java project</description> 
    <property name="srcDir" location="src"/>
    <property name="buildDir" location="build"/>
    <property name="distDir" location="dist"/>
    <target name="init">
       <tstamp/>
       <mkdir dir="${buildDir}"/>
       <mkdir dir="${distDir}"/>
    </target>
    <target name="compile" depends="init">
       <javac srcdir="${srcDir}" destdir="${buildDir}"/>
    </target>
    <target name="dist" depends="compile">
       <jar destfile="${distDir}/package-${DSTAMP}.jar" basedir="${buildDir}">
         <manifest>
           <attribute name="Built-By" value="${user.name}"/>
           <attribute name="Main-Class" value="package.Main"/>
         </manifest>
       </jar>
       <jar destfile="${distDir}/package-src-${DSTAMP}.jar" basedir="${srcDir}"/>
    </target>
    <target name="clean">
      <delete dir="${buildDir}"/>
      <delete dir="${distDir}"/>
    </target>
</project>


下面是使用该文件执行的某次生成过程的示例输出(您得到的输出可能不一样,具体取决于 src 目录的

内容):


Buildfile: build.xml
init:
    [mkdir] Created dir: E:/tutorial/javaexample/build
    [mkdir] Created dir: E:/tutorial/javaexample/dist
compile:
    [javac] Compiling 10 source files to E:/tutorial/javaexample/build
dist:
      [jar] Building jar: E:/tutorial/javaexample/dist/package-20031217.jar
      [jar] Building jar: E:/tutorial/javaexample/dist/package-src-20031217.jar
BUILD SUCCESSFUL
Total time: 5 seconds


注意 JAR 文件是根据当前日期来命名的,并且为应用程序的主类设置了一个清单条目,以便主类能够通

过一个简单的命令 java -jar package-20031217.jar 来直接运行。我们还创建了一个 JAR 文件,它仅

包含项目的源代码。

文件操作系统
我们了解了关于 Ant 的足够多的知识,现在能够生成一个基本的 Java 项目了,不过现实中的项目当然

很少像我们的例子那样简单。在下面几节中,我们将考察 Ant 的许多附加功能中的一部分,以及能够使

用它们的场合。

在本节中,我们将考察如何执行常见文件操作,比如创建目录和解压缩文件。 Ant 的优秀特性之一在于

,执行这些操作的任务一般在所有平台上都是相同的。


创建和删除目录

 


最基本的文件系统操作之一就是创建目录或文件夹。做这项工作的任务名为 mkdir,毫不奇怪,它非常

类似于具有相同名称的 Windows 和 UNIX/Linux 命令。


<mkdir dir="archive/metals/zinc"/>


首先要注意 / 被用作目录分隔符,这是 UNIX 和 Linux 的惯例。您可能认为这不是很平台无关的,但

是 Ant 知道如何处理它,并针对它运行所在的平台做恰当的事情,这与我们在前面定义基于位置的属性

时所看到的方式相同。我们能够同样容易地使用 /,而不管平台是什么 ―― Ant 能够处理任一种形式

,甚至能够处理两种形式的混合。

mkdir 任务的另一个有用特性是它的如下能力:在父目录还不存在时创建它们。考虑一下上面的清单,

设想 archive 目录存在,但是 metals 目录不存在。如果使用底层平台的 mkdir 命令,您需要首先显

式地创建 metals 目录,然后第二次调用 mkdir 命令来创建 zinc 目录。但是 Ant 任务比这更加智能

,它能够一次性创建这两个目录。类似地,如果目标目录已经存在,mkdir 任务不会发出错误消息,而

只是假设它的工作已经完成,从而什么也不做。

删除目录同样也很容易:


<delete dir="archive/metals/zinc"/>


这将删除指定的目录连同它包含的所有文件以及子目录。使用 file 属性而不是 dir 属性可以指定要删

除的单个文件。

复制和移动文件

在 Ant 中制作文件的一份拷贝很简单。例如:


<copy file="src/Test.java" tofile="src/TestCopy.java"/>


您还可以使用 move 来执行重命名操作而不是拷贝文件:


<move file="src/Test.java" tofile="src/TestCopy.java"/>


另一个常用的文件系统操作是将文件复制或移动到另一个目录。做这项工作的 Ant 语法同样也很简单:


<copy file="src/Test.java" todir="archive"/>
<move file="src/Test.java" todir="archive"/>


默认情况下,Ant 仅输出它执行的移动和复制操作的摘要,包括诸如已移动或复制的文件的数量等信息

。如果想看到更详细的信息,包括涉及的文件名称等,您可以将 verbose 属性设置为true。

 

创建与解压缩ZIP和TAR文件

在前一节中,我们看到了如何创建 JAR 文件。创建其他归档文件的过程几乎完全相同。下面是创建 zip

文件的 Ant 任务:


<zip destfile="output.zip" basedir="output"/>


相同的语法也可用于创建 tar 文件。 还可以使用 GZip 和 BZip 任务来压缩文件。例如:


<gzip src="/developerWorks/cn/education/java/j-apant/tutorial/output.tar"

zipfile="output.tar.gz"/>


解压缩和提取文件同样也很简单:


<unzip src="/developerWorks/cn/education/java/j-apant/tutorial/output.tar.gz"

dest="extractDir"/>


还可以包括 overwrite 属性来控制覆盖行为。默认设置是覆盖与正在被提取的归档文件中的条目相匹配

的所有现有文件。相关的任务名称是 untar、unjar、gunzip 和 bunzip2。

替换文件中的标记

我们将在本节考察的最后一个文件系统操作是 replace 任务,它执行文件中的查找和替换操作。token

属性指定要查找的字符串,value 属性指定一个新的字符串,查找到的标记字符串的所有实例都被替换

为这个新的字符串。例如:


<replace file="input.txt" token="old" value="new"/>


替换操作将在文件本身之内的适当位置进行。为了提供更详细的输出,可把 summary 属性设置为 true

。这将导致该任务输出找到和替换的标记字符串实例的数目。


其它有用的任务和技术

在考察自定义的任务之前,我们首先介绍一些还没遇到过的有用功能。Ant 标准地附带了大量的功能,

因此这里仅经挑选其中几个最有用的功能。模式匹配和文件选择器是功能强大的机制,它们极大地增强

了我们已看到过的一些任务的功能;将生成任务链接起来以及与 CVS 知识库协同工作,是已发现的这些

机制的两个主要实际应用领域。

 


模式匹配 
在前面考察文件系统任务时,我们仅使用了单独地命名的文件和目录。然而,一次对一组文件执行那些

操作经常是有用的 ―― 例如对给定目录中以 .java 结尾的所有文件执行操作。正如等价的 DOS 和

UNIX 命令提供了这样的功能一样,Ant 也提供了这样的功能。这是使用通配符字符来完成的:*,它匹

配零个或多个字符;以及 ?,它仅匹配一个字符。因而匹配以 .java 结尾的所有文件的模式不过就是

*.java。

也可以对目录执行模式匹配。例如,模式 src*/*.java 将匹配带 src 前缀的任何目录中的所有 Java

文件。 还有另一种模式结构:**,它匹配任意数量的目录。例如,模式 **/*.java 将匹配当前目录结

构下的所有 Java 文件。

您能够以相当一致的方式对文件系统任务使用模式,比如嵌套的 fileset 元素。先前,我们使用这个任

务来复制单个文件:


<copy file="src/Test.java" todir="archive"/>


如果我们想要使用一个模式,可以将 file 属性替换为一个 fileset 元素,如下所示:


<copy todir="archive">
  <fileset dir="src">
    <include name="*.java"/>
  </fileset>
</copy>


fileset 默认情况下包含指定 src 目录下的所有文件,因此为了仅选择 Java 文件,我们对模式使用一

个 include 元素。类似地,我们可以对另一个模式添加一个 exclude 元素,从而潜在地排除include指

定的匹配项。甚至可以指定多个include 和 exclude 元素;这样将得到一组文件和目录,它们包含

include 模式的所有匹配项的并集,但排除了 exclude 模式的所有匹配项。

注意还有一个通常很有用的文件集特性,但是对于没有意识到它的人来说,这个特性偶尔会产生混淆。

这个特性称为 默认排除:即自动从文件集内容中排除的内置模式列表。该列表包括与名为 CVS 的目录

相匹配的条目,以及以 ~ 字符结尾的文件,它们可能是备份文件。您通常不想在文件系统操作中包括这

类文件和目录,因此排除这些文件是默认行为。然而,如果确实想无例外地选择 所有 文件和目录,可

以将文件集的 defaultexcludes 属性设置为 no。

使用选择器
正如我们已经看到的,文件集用于指定一组文件,并且这个组的内容可以使用 include 和 exclude 模

式来指定。也可以结合称为 选择器 的特殊元素使用include 和 exclude 来选择文件。下面是对 Ant

可用的核心选择器的列表:

size:这个选择器用于根据文件的字节大小选择文件(除非使用 units 属性来指定了不同的单位)。

when 属性用于设置比较的性质(less、more 或者 equal),value 属性定义每个文件将与之作比较的

目标大小。


contains:只有包含给定文本字符串(由text 属性指定)的文件才匹配这个选择器。默认情况下,查找

操作是大小写敏感的;添加casesensitive="no" 可以改变默认设置。


filename:name 属性指定文件名要与之匹配的模式。它本质上与 include 元素相同,以及与指定了

negate="yes" 时的 exclude 元素相同。


present:从当前目录结构中选择如下文件:它们与指定的 targetdir 目录中的文件具有相同的名称和

相对目录结构。


depend:这个选择器与 present 选择器具有相同的效果,只不过匹配的文件被限制到相对于 targetdir

位置中的对应文件来说,最近已修改过的那些文件。


date:这个选择器基于其最后修改日期选择文件。when 属性指定作比较的性质是 before、after 还是

equal,datetime 属性指定与之作比较的日期和时间,这个日期和时间具有给定的固定格式 MM/DD/YYYY

HH:MM AM_or_PM。注意 Windows 平台上有一个内置的 2 秒偏移,以允许底层文件系统的不精确性 ――

这可能导致匹配的文件数量超过预期。允许的回旋时间量可以使用 granularity 属性来更改(以毫秒为

单位来指定)。


depth:这个选择器检查每个文件的目录结构层次数目。min 和/或 max 属性用于选择具有想要的目录层

次数目的的文件。
还可以通过在一个选择器 容器 内嵌套一个或多个选择器来组合选择器。 最常用的选择器容器 and 仅

选择它包含的所有选择器都选择了的文件。其他选择其容器包括 or、not、none 和 majority。

下面是一个文件集的例子,它仅选择那些大于 512 字节并且包含字符串“hello”的文件。


<fileset dir="dir">
    <and>
        <contains text="hello"/>
        <size value="512" when="more"/>
    </and>
</fileset>


将生成文件链接起来
有两种生成大型项目的不同方法。一种是让一个单一的生成文件做所有事情;另一种是让高级别的生成

文件调用其它生成文件以执行特定任务,从而将生成过程划分为许多较小的部分。

使用 ant 任务来从一个 Ant 生成中调用另一个 Ant 生成是很容易的。在简单的情况下,您可以使用

antfile 属性,仅指定那些要使用的生成文件,Ant 将生成该生成文件中的默认目标。例如:


<ant antfile="sub-build.xml"/>


在父生成文件中定义的任何属性默认将传递给子生成文件,虽然这可以通过指定 inheritAll="false"来

避免。通过使用 property 元素来传入显式的属性也是可以做到的 ―― 即使将 inheritAll 设置为

false,这些属性也仍然适用于子生成文件。这个功能很适合用于给子生成文件传入参数。

让我们来考虑一个例子。下面是我们想要调用的一个生成文件:


<?xml version="1.0"?>
<project default="showMessage">
    <target name="showMessage">
        <echo message="Message=${message}"/>
    </target>
</project>


(我们在前面还没有遇到过 echo 任务 ―― 它简单地输出给定的消息。)

下面是调用第一个生成文件的第二生成文件,它还给第一个生成文件传入 message 属性:


<?xml version="1.0"?>
<project default="callSub">
    <target name="callSub">
        <ant antfile="sub.xml" target="showMessage" inheritAll="false">
            <property name="message" value="Hello from parent build"/>
        </ant>
    </target>
</project>


运行第二个生成文件所得到的输出如下:


Buildfile: build.xml
callSub:
showMessage:
     [echo] Message=Ht build
BUILD SUCCESSFUL
Total time: 0 seconds


使用自定义任务来定制ANT

正如我们从前述几节中所看到的,Ant 非常强大,具有涵盖广泛功能集的许多核心任务。它还有许多这

里没有介绍的附加任务,再加上提供广泛附加功能的许多可选任务,以及作为 Ant-Contrib 项目的一部

分来提供的其他任务;最后,Apache Ant 主页上还列出了外部可用的更多任务。面对 Ant 提供的所有

这些任务,您似乎再也不需要其他任务了,但是 Ant 的真正力量在于它的易于扩展性。事实上,恰恰正

是这种可扩展性促使人们开发了如此多的附加任务。

可能会存在这样的场合,在那样的场合下创建自定义的任务更为合适。例如,假设您创建了一个命令行

工具来执行某个特定操作;这个工具可能是将对 Ant 可用的任务的恰当候选者(当该工具是用 Java 语

言编写的时更是这样,虽然该工具不一定是用 Java 语言编写的。)与其让 Ant 使用 exec 任务外部地

调用该工具(这样将引入依赖关系,并使得生成文件在跨越不同平台时更难于使用),您可以将它直接

合并到生成文件中。还可以使得 Ant 的常规文件集和通配符匹配功能对自定义的任务可用。

在本节中,我们将考察一个简单自定义任务的构造过程。这个任务将对文件中的行执行排序操作,并将

排序后的行集写到一个新文件中。


创建自定义的任务 第 2 页(共4 页)

 


为实现一个简单的自定义任务,我们所需做的就是扩展 org.apache.tools.ant.Task 类,并重写

execute() 方法。因此,作为这个文件排序自定义任务的框架,我们将编写如下代码:


import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
public class FileSorter extends Task {
       // The method executing the task
       public void execute() throws BuildException {}
}


注意我们声明 execute() 方法抛出一个 BuildException 异常。如果这个任务出了任何错误,我们将抛

出这个异常以便向 Ant 指出故障。

大多数任务,不管是核心任务还是自定义任务,都利用属性来控制它们的行为。对于这个简单任务,我

们需要一个属性来指定要排序的文件,需要另一个属性来指定排序内容的输出。我们把这两个属性分别

叫做 file 和 tofile。

Ant 使得支持自定义任务中的属性非常容易。为此,我们只需实现一个具有特别格式化的名称的方法,

Ant 能够使用生成文件中指定的对应属性的值来调用这个方法。这个方法的名称需要是 set 加上属性的

名称,因此在这个例子中,我们需要名为 setFile() 和 setTofile() 的方法。当 Ant 遇到生成文件中

的一个属性设置时,它会寻找相关任务中具有适当名称的方法(称为 setter 方法)。

生成文件中的属性是作为字符串来指定的,因此我们的 setter 方法的参数可以是一个字符串。在这样

的情况下,Ant 将在展开值所引用的任何属性之后,使用该属性的字符串值来调用我们的方法。但有时

我们想把属性的值看作是一种不同的类型。这里的示例任务就是这种情况,其中的属性值引用文件系统

上的文件,而不只是引用任意的字符串。可以通过将方法参数声明为 java.io.File 类型来容易地做到

这点。Ant 将接受属性的字符串值,并把它解释为一个文件,然后传递给我们的方法。如果文件是使用

相对路径名称来指定的,则会被转换为相对于项目基目录的绝对路径。Ant 能够对其他类型执行类似的

转换,比如 boolean 和 int 类型。如果您提供具有相同名称但是具有不同参数的两个方法,Ant 将使

用更明确的那一个方法,因此文件类型将优先于字符串类型。

这个自定义任务需要的两个 setter 方法类似如下:


    // The setter for the "file" attribute
    public void setFile(File file) {}
    // The setter for the "tofile" attribute
    public void setTofile(File tofile) {}

实现自定义的任务 第 3 页(共4 页)

 


使用前一小节开发的框架,现在我们能够完成这个简单的文件排序任务的实现:


import java.io.*;
import java.util.*;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
/**
 * A simple example task to sort a file
 */
public class FileSorter extends Task {
    private File file, tofile;
   
    // The method executing the task
    public void execute() throws BuildException {
        System.out.println("Sorting file="+file);
        try {
            BufferedReader from =
                new BufferedReader(new FileReader(file));
            BufferedWriter to =
                new BufferedWriter(new FileWriter(tofile));
            List allLines = new ArrayList();
            // read in the input file
            String line = from.readLine();
            while (line != null) {
                allLines.add(line);
                line = from.readLine();
            }
            from.close();
            // sort the list
            Collections.sort(allLines);
            // write out the sorted list
            for (ListIterator i=allLines.listIterator(); i.hasNext(); ) {
                String s = (String)i.next();
                to.write(s); to.newLine();
            }
            to.close();
        } catch (FileNotFoundException e) {
            throw new BuildException(e);
        } catch (IOException e) {
            throw new BuildException(e);
        }
    }
    // The setter for the "file" attribute
    public void setFile(File file) {
        this.file = file;
    }
    // The setter for the "tofile" attribute
    public void setTofile(File tofile) {
        this.tofile = tofile;
    }
}


使用自定义的任务 第 4 页(共4 页)

 


现在我们已经开发和编译了这个自定义的任务,下面可以从生成文件中利用它了。

在能够调用自定义的任务之前,我们需要给它指定一个名称来 定义 它,并告诉 Ant 关于实现这个任务

的类文件的信息,以及定位该类文件所必需的任何 classpath 设置。这是使用 taskdef 任务来完成的

,如下所示:


<taskdef name="filesorter"
    classname="FileSorter"
    classpath="."/>


大功告成!现在可以像使用 Ant 的核心任务一样使用这个自定义的任务了。下面是一个完整的生成文件

,它显示了这个自定义任务的定义和用法:

<?xml version="1.0"?>
<project name="CustomTaskExample" default="main" basedir=".">
    <taskdef name="filesorter"
        classname="FileSorter
       classpath="."/>
    <target name="main">
        <filesorter file="input.txt" tofile="output.txt"/>
    </target>
</project>


现在在当前工作目录中创建一个 input.txt 文件来测试这个自定义的任务。例如:


Hello there
This is a line
And here is another one


下面是运行上面的生成文件之后产生的控制台输出:


Buildfile: build.xml
main:
[filesorter] Sorting file=E:/tutorial/custom/input.txt
BUILD SUCCESSFUL
Total time: 0 seconds


注意 input.txt 的相对路径名称被转换成了当前目录中的一个绝对路径名称。这是因为我们将 setter

方法的参数指定为 java.io.File 类型而不是 java.lang.String 类型。

现在看一下这个任务实际是否能工作。这时应该已经在同一目录中创建了名为 output.txt 的文件,它

包含以下内容:


And here is another one
Hello there
This is a line


您可以尝试指定一个不存在的输入文件,以确定该任务是如何向 Ant 报告 “file not found”异常的

祝贺您:您现在已经开发和使用了一个自定义的 Ant 任务!创建更复杂的任务还会涉及其他许多方面,

参考资料包含了指向此主题的进一步信息源的链接。

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值