Ant详解-
简介:(构建工具)
Apache Ant是一个基于Java的自动生成工具。工具全名是Another Neat Tool的首字母所写。
Apache Ant是一个Java的Library 也是一个命令行,他的任务是驱动构建文件的开发,并且这些文件是以目标(targets)和扩展点(extension)的形式描述,两者互相依赖。
它最常用的使用方式是用来构件Java应用的。
Ant提供了大量内置任务可以进行"编译","装配","测试"和运行Java应用程序.
Ant也可以用来高效的去构建非Java应用,例如C和C++应用程序.
Ant还可以用来进行过程的处理,表现为通过目标(target)和任务(tasks)的方式进行.
Ant是用Java来进行编写的,用户可以开发他们自己的Ant Library(类似于插件).
Ant非常灵活,并没有强制的代码的约定,或是目录层次的约定,因此可以作为一个构件工具来使用.
将Ant压缩包下载下来之后,解压得到如下文件:

最重要的是前面四个目录中的内容:
bin:与tomcat的bin文件一样,是批处理文件,对应于linux系统中是.sh文件(最重要);
lib:是依赖库;
etc:是外部的依赖文件;
manual:是apache website上相关说明的一个离线的版本.
配置ANT: Ant-07:00
若想使用ant,首先需要将bin目录放置于环境变量PATH下面(类似于配置Java虚拟机):
1. 配置Ant_HOME环境变量:

2.配置Path环境变量:

3. 测试配置是否成功:

Ant的作用: Ant-11:00
Ant生成工具在软件开发中用来将源代码和其他输入文件转换成为可执行的目标文件的形式(也有可能转换为可安装的产品映像形式);
随着应用程序的生成过程变得更加复杂,确保在每次生成期间都使用精确相同的生成步骤,同时实现尽可能多的自动化,以便及时产生一致的生成版本,这就变得更加重要;
Ant的优势:
Ant定义生成文件之间的依赖关系,它使用跨平台的Java类.使用Ant,你能够编写单个生成文件,这个生成文件在任何Java平台上都一致的操作(因为Ant本身也是使用Java语言来实现的),这是Ant的最大优势.
Ant是通过编写XML文件进行构建的 Ant-13:00
Ant默认的XML文件名称就是build.xml,也就是启动ant的时候会在当前目录下面寻找build.xml配置文件.
<?xml version="1.0" encoding="utf-8"?> <project default="init"> <target name="init"> <!-- 利用ant创建目录 --> <mkdir dir="helloworld\a\b\c" /> </target> </project>
将build.xml文件放置于目标目录中,这里放置于E盘:
然后运行ant:

在E盘中查看,可以发现,目录已经创建成功,而且还是嵌套的子目录结构:

修改xml文件如下:
<?xml version="1.0" encoding="utf-8"?> <project default="init"> <target name="init"> <!-- 利用ant创建目录 --> <delete dir="helloworld\a\b\c" /> </target> </project>
再次运行ant,

发现E盘中的嵌套的多个目录将会全部被删除掉。(这里比Java要方便的多,因为Java中删除某一个目录的时候,该目录必须为空,否则删除会失败)
解释:build.xml中的根元素是<project>,一个<project>下面可以有多个<target>元素,一个<target>元素就是一个目标,为了完成一个任务,当然多个<target>之间也可以存在相互协作的关系,可以包含<target>执行的顺序问题.
编写ant的主要部分都是在编写build.xml文件.
当然也可以不使用build.xml规定的文件名,可以自己指定文件名(但是几乎所有的公司都会将ant的配置文件定义成为build.xml):
ant -f hello.xml

即可.
Ant没有定义它自己的语法;相反,它的生成文件使用xml编写的.存在一组ant能够理解的预定义xml元素,而且还可以定义新的元素来扩展Ant的功能(例如在build.xml中自定义一些新的标签)。每个生成文件由单个project元素组成,该元素又包含一个或多个target元素。一个目标(target)是生成过程中已定义的一个步骤,他执行任意数量的操作,比如编译一组源文件。并且这些操作本身是由其他专用任务标签执行的(例如上例中的<mkdir>和<delete>元素)。 Ant-20:00 注意26:00解释,通过日志来查看任务是否执行完成.
Ant生成文件剖析: Ant-28:30
这些任务将根据需要被分组到各个<target>元素中。一次生成过程所必须的所有操作可以放入单个target元素中,但是那样会降低灵活性。将那些操作划分为逻辑生成步骤,每个步骤包含在它自己的target元素中,这样通常更为可取。这样可以执行整体生成过程的单独部分,却不一定必须执行其他部分。
例如:通过仅仅调用某些目标,你可以编译项目的源代码,却不必创建可安装的项目文件。
指定<target>元素执行的顺序:
例如:
<?xml version="1.0" encoding="utf-8"?> <project default="second"> <target name="init"> <delete dir="hello" /> <delete dir="world" /> <delete dir="welcome" /> </target> <target name="second"> <mkdir dir="hello" /> <mkdir dir="world" /> <mkdir dir="welcome" /> </target> </project>
这里可以通过修改default的值来执行指定的target元素。
可以指定target执行的顺序,通过在target元素中加入depends属性来指定依赖关系,也就是执行的顺序。
<?xml version="1.0" encoding="utf-8"?> <project default="second"> <target name="init"> <!-- 创建目录 --> <mkdir dir="hello" /> <mkdir dir="world" /> <mkdir dir="welcome" /> </target> <target name="second" depends="init"> <!-- 删除目录 --> <delete dir="hello" /> <delete dir="world" /> <delete dir="welcome" /> </target> </project>
执行这个build.xml如下:

顶级的<project>元素project元素需要包含一个default属性,如果在Ant被调用时没有指定目标,这个属性将指定要执行的目标。然后需要使用target元素来定义目标本身。 Ant-35:00
当我们指定target的时候,将会忽略default属性,转而执行我们指定好的target内容。
例如:

这里我们显式的指定了我们要执行的目标到底是什么。
如果要在一行命令中执行多个目标,可以在ant命令之后添加多个target的name属性值,如下:

更多信息:
1 <?xml version="1.0" encoding="utf-8"?> 2 <project default="second" name="Project"> 3 4 <description> 5 当前元素仅仅是一个描述性的信息,类似于注释 6 </description> 7 <!-- 当然也可以使用注释 --> 8 9 <target name="init"> 10 <!-- 创建目录 --> 11 <mkdir dir="hello" /> 12 <mkdir dir="world" /> 13 <mkdir dir="welcome" /> 14 </target> 15 16 <!-- target中可以增加一个属性description,同样也是起到一个说明的作用 --> 17 <target name="second" depends="init" description="hello world"> 18 <!-- 删除目录 --> 19 <delete dir="hello" /> 20 <delete dir="world" /> 21 <delete dir="welcome" /> 22 </target> 23 24 </project>
三个地方可以增加描述性信息,Line4,Line7,Line17
XML注释可以使用在整个生成文件中以提高清晰性.而且,Ant定义了它自己的description元素和description属性,它们可以用于提供更加结构化的注释.
Ant属性: Ant2-00:00
Ant中的属性类似于变成语言中的变量,它们都是具有名称和值的,类似于.properties文件格式。然而与通常变量不同,一经设置,Ant中的属性就是不可更改的;它们是常量,就想Java语言中的String对象一样。
这起初看起来似乎有很大的限制性,但是这样是为了遵循Ant简单的原则:毕竟,它是一个生成工具,而不是一种编程语言。
如果尝试给某个现有属性赋予一个新的值,这不会被看做一个错误,但是该属性仍然会保留其现有值。类似于Java中的常量一样,一旦定义完之后不能被改变。
定义属性:
<property name="metal" value="beryllium" />
为了在生成文件的其他部分引用这个属性,使用以下语法:
${metal}
例如为了使用这样一个属性值,它是另一个属性值的组成部分,可以将标签写成下面这样:
<property name="metal-database" value="${metal}.db" />
属性可以插入到任何一个其他的地方.
注意:Ant的build.xml文件中的元素是没有顺序的,例如<target>元素,他们之间的执行顺序是通过<target>元素中的depends属性来指定的,而不是元素在文件中的书写顺序来指定的. Ant2-02:20
如果在执行某个<target>元素的时候发现当前<target>元素depends另外一个<target>元素,那么Ant会去先执行另外这个<target>元素中的任务,执行完成后才会回来执行当前这个<target>中的内容.但是需要注意的是不能出现循环depends的情况,这样就会变成死循环.
属性举例:
修改build.xml内容如下:
<?xml version="1.0" encoding="utf-8"?> <project default="second" name="Project"> <description> 当前元素仅仅是一个描述性的信息,类似于注释 </description> <!-- 当然也可以使用注释 --> <property name="hello" value="welcome" /> <target name="init"> <!-- 创建目录 --> <mkdir dir="hello" /> <mkdir dir="world" /> <mkdir dir="${hello}" /> </target> <!-- target中可以增加一个属性description,同样也是起到一个说明的作用 --> <target name="second" depends="init" description="hello world"> <!-- 删除目录 --> <delete dir="hello" /> <delete dir="world" /> <delete dir="welcome" /> </target> </project>
运行Ant可得:

属性只要定义完成之后可以任意的插入到其他地方.
location属性 Ant2-05:00
属性经常用于引用文件系统上的文件或者是目录,但是对于使用不同路径分隔符(例如"/"和"\")的平台来说,这样可能在跨越不同平台的时候导致问题。Ant的location属性专门用于以平台无关的方式包含文件系统路径。
例如:
<property name="database-file" location="archive/databases/${metal}.db" />
或者:
<property name="database-file" location="archive\databases\${metal}.db" />
这里的属性location就具有了跨平台的特征,在windows和Linux上具有相同的路劲表达意义。以上这两个标签具有相同的意义.
用于location属性的路径分隔符将被转换成为当前平台的正确格式;而且由于文件名是相对的,它被认为是相对于项目的根目录.
再谈depends属性:
生成一个项目一般需要许多步骤----例如首先需要编译源代码,然后将它打包为归档文件(Jar)。这其中许多步骤具有清楚定义的顺序 -- 例如,在编译器从源代码生成类文件之前,您不能打包类文件。
与顺序指定target执行序号所不同的是,Ant采用一种更灵活的方式来定义依赖关系。每个目标的定义依据的是在它能够执行之前必须完成的其他所有<target>,这是使用<target>元素的depends属性来实现的
例如: Ant2-07:40
<target name="init" /> <target name="preprocess" depends="init" /> <target name="compile" depends="init,preprocess" /> <target name="package" depends="compile" />
当一个<target>元素依赖于多个其他的<target>元素的时候,可以是用逗号隔开.
注意当init执行完成之后,将不会在执行该<target>元素中的内容了.
如下:
<?xml version="1.0" encoding="utf-8"?> <project default="second" name="Project"> <target name="init"> <!-- 创建目录 --> <mkdir dir="hello" /> <mkdir dir="world" /> <mkdir dir="welcome" /> </target> <target name="second" depends="init" description="hello world"> <!-- 删除目录 --> <delete dir="hello" /> <delete dir="world" /> <delete dir="welcome" /> </target> </project>
这里与在命令中显式敲入ant init second不一样,当再命令行中显式敲入<target>名称的时候,init会执行两次;
在上一个例子中,当敲入package时,init目标仅仅会在执行compile元素之前执行一次,在执行preprocess目标时不会再去执行init了。
这种方法允许你执行项目的任何阶段的生成过程;Ant首先会执行已定义的先决阶段,在上一例中,如果让Ant完成compile步骤,它将判断出需要首先执行init和preprocess这两个目标。init不依赖于其他任何目标,因此它将首先被执行。然后ant检查preprocess <target>,发现它依赖于init <target>;由于已经执行了init,Ant不会再次执行它,而是开始执行preprocess目标,最后才去执行compile <target>本身.
注意<target>在build.xml文件中出现的顺序并不重要,执行的顺序是由depends属性唯一确定的.
执行结果如下: Ant2-10:00

可以看见,init仅仅被执行了一次,没有出现两次的情况,虽然每个<target>中并没有出现任何逻辑
利用Eclipse创建build.xml文件: Ant2-15:00
一般情况,build.xml文件都放置在项目的根目录下面:(在任何工程中都可以使用Ant进行构建)
创建如下:
在eclipse中的目标项目上点击右键,然后new一个xml文件,取名为build.xml,默认情况下,eclipse没有将该文件关联为Ant editor中,这里可以在Window -> preference -> General -> Editor -> File Association 中指定:

这样在工程就就可以看见xml文件关联上了Ant Editor工具,这样在编写build.xml文件的时候就会出现代码提示和相关的错误指示信息。

然后在文件上右键 -> Run As Ant Build即可执行

可以在<project>根元素中加入basedir属性来指定输出的相对路径,如下 Ant002-22:00
<?xml version="1.0" encoding="UTF-8"?> <project name="AntTest" basedir="." default="package"> <property name="hello" value="hello123"></property> <property name="world" value="world123"></property> <target name="init"> <mkdir dir="${hello}"/> <mkdir dir="${world}"/> </target> <target name="preprocess" depends="init"></target> <target name="compile" depends="init,preprocess"></target> <target name="package" depends="compile"></target> </project>
当然也可以对Ant的配置文件build.xml进行调试,与普通的Java代码调试方式一样,只不过这次的源代码是XML文件,而不是Java代码. Ant2-23:0

可以在eclipse中选择执行project中指定的<target>元素.
右键 -> Run As -> 2 Ant Build ...


这样,Ant就会自动去执行preprocess<target> 而不是去执行默认的package<target>
eclipse中提供了一个非常方便快捷的视图: Ant View Ant2-25:00

这样,在这个视图中,当你想运行某个<target>的时候,你双击它就可以直接运行当前<target>了.
Eclipse由于已经内建了Ant工具所需的各种库以及配置,因此我们可以直接拿来就用,不用去自己进行配置.在项目中也是一样的,主要的Ant工作就是编写build.xml文件.
默认情况下,Ant寻找一个名为build.xml的文件。因此,如果您的生成文件使用这个名称,就不需要在命令行指定他。当然,有时使用具有其他名称的生成文件更方便,在那样的情况下,您需要对Ant使用
-buildfile <file> 或 -f <file>
另一个有用的选项是-D,它用于设置随后可以在生成文件中使用的属性。这对于配置你想要以某种方式开始的生成过程是非常有用的。 Ant003-04:00
例如,为了将name属性设置为某个特定的值,您会使用一个类似于下这样的选项:
-Dmetal=beryllium
注意这里的-D和后面的属性名称是没有任何分隔符的,一定要连续写。
这个功能可用于覆盖生成文件中的初始属性值。正如前面指出过的,属性值一经设置就不能改变。
-D标志在读取生成文件中的任何信息之前设置某个属性:由于生成文件中的指派落在这个初始指派之后,因此它不会改变其值。
IDE集成 Ant003-07:00
Ant对Java集成的非常紧密,它可以帮助我们编译Java源代码,编译完成之后还可以帮我们打包成为Jar文件。这些功能都是通过Ant内置的标签元素实现的,实际上每一个标签都对应Ant库中的一个处理类。
编译源代码:
<javac srcdir="src" />
这个标签寻找src目录中以.java为扩展名的所有文件,并对它们调用javac编译器,从而在相同的目录中生成类文件。当然,将类文件放在一个单独的目录结构中通常会更清晰,这个可以通过添加destdir属性来让Ant做到这一点。如果不指明destdir,则Ant会在相应的.java文件所在的目录放置编译好的.class文件。

通常情况下,我们是在单独的一个目录中保持我们声称的.class各种文件,而不是在源代码目录中放置.class文件。
如下:
<?xml version="1.0" encoding="UTF-8"?> <project name="AntTest" basedir="." default="myCompile"> <property name="compile" value="compile"></property> <target name="preprocess"> <mkdir dir="${compile}"/> </target> <target name="myCompile" depends="preprocess"> <javac srcdir="src" destdir="${compile}"></javac> </target> </project>
生成的编译好的文件如下:

生成好的目录结构仍然是按照包名进行组织的。
还有其他一些有用的属性: Ant003-13:00
-classpath:等价于javac的-classpath选项。(指定类路径)
-debug=“true”:指示编译器应该带有调试信息编译源文件。
javac任务的一个重要特点在于,它仅编译那些它认为需要编译的源文件。如果某个类文件已经存在,并且对应的源文件自从该类文件生成以来就没有被改变过,那么该源文件就不会被重新编译;
javac任务的输出显示了实际被编译的源文件的个数;

该行为刻画了Ant的许多任务特点:如果某个任务能够确定所请求的操作不需要执行,那么该操作就会被跳过。(与删除目录或者创建目录的意义相同)
创建Jar文件
在编译好Java源文件之后,结果.class文件通常被打包到一个Jar文件中,这个文件类似zip归档文件。每个Jar文件都包含一个清单文件,他可以指定该Jar文件的属性。
下面是Ant中jar任务的一个简单使用例子:
<jar destfile="package.jar" basedir="classes" />
这就会创建一个名为package.jar的Jar文件,并且把classes目录中的所有文件添加到其中(jar文件能够包含任意类型的文件,而不只是.class文件,只不过.class文件是最主要的内容,不过配置文件也会通常打包至Jar文件中)
此处没有指定清单文件,因此Ant将自动生成一个基本的清单文件.
解压Jar文件可以看到里面Ant会自动生成一个META-INF目录,里面有一个清单文件MANIFEST.MF里面有相应的说明清单,如下: Ant003-09:00

如果要能直接双击Jar文件自动运行里面的程序,需要在清单文件MANIFEST.MF中添加main class入口(主类),不过限于图形界面,现举例如下:
这里需要在<jar>元素中指定子元素<manifest>,这里可以填入清单相关的内容,具体Ant代码如下:
<?xml version="1.0" encoding="UTF-8"?> <project name="AntTest" basedir="." default="dist"> <property name="compile" value="compile"></property> <target name="preprocess"> <mkdir dir="${compile}"/> </target> <target name="myCompile" depends="preprocess"> <javac srcdir="src" destdir="${compile}"></javac> </target> <target name="dist" depends="myCompile"> <jar destfile="package.jar" basedir="${compile}"> <manifest> <attribute name="Built-By" value="${user.name}" /> <attribute name="Main-Class" value="cn.edu.bupt.ant.AntUI" /> </manifest> </jar> </target> </project>
注意<manifest> 和 <attribute>标签:
这样运行Ant之后生成的Jar文件中的清单文件如下:

双击后可以直接运行。
说明:<manifest>属性允许指定一个用作该Jar文件的清单文件。清单文件的内容还可以使用manifest任务在生成文件中指定。这个任务能够想文件系统中写入一个清单文件,或者能够实际嵌套在Jar之内,以便一次性的创建清单文件和Jar文件。
时间戳的生成 Ant003-28:00
在生成环境中使用当前日期和事件,以某种方式标记某个生成任务的输出,以便记录它是何时生成的,这经常是可取的。这可能涉及到编辑一个文件,以便插入一个字符串来指定日期和时间,或将这个信息合并到Jar文件或zip文件中.
这种需求在Ant中是通过简单但是非常有用的tstamp任务来解决的。这个任务通常是在某次生成过程的开始调用,比如在一个init <target>中。这个任务不需要属性,许多情况下只需要<tstamp /> 就足够了。
tstamp不产生任何输出;相反,它根据当前系统时间和日期设置Ant属性。下面是tstamp设置的一些属性、对于每个属性的说明,以及这些属性可被设置到的值的例子:

在调用tstamp任务之后,我们能够根据日期命名该Jar文件,如下所示:
<jar destfile="package-${DSTAMP}.jar" basedir="classes">
具体使用如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project name="AntTest" basedir="." default="dist"> 3 <!-- 4 <property name="hello" value="hello123"></property> 5 <property name="world" value="world123"></property> 6 7 <target name="init"> 8 <mkdir dir="${hello}"/> 9 <mkdir dir="${world}"/> 10 </target> 11 12 <target name="preprocess" depends="init"></target> 13 <target name="compile" depends="init,preprocess"></target> 14 <target name="package" depends="compile"></target> 15 --> 16 17 <property name="compile" value="compile"></property> 18 <target name="preprocess"> 19 <tstamp></tstamp> 20 <mkdir dir="${compile}"/> 21 </target> 22 <target name="myCompile" depends="preprocess"> 23 <javac srcdir="src" destdir="${compile}"></javac> 24 </target> 25 26 <target name="dist" depends="myCompile"> 27 <jar destfile="package-${DSTAMP}.jar" basedir="${compile}"> 28 <manifest> 29 <attribute name="Built-By" value="${user.name}" /> 30 <attribute name="Main-Class" value="cn.edu.bupt.ant.AntUI" /> 31 </manifest> 32 </jar> 33 </target> 34 </project>
注意在Line19声明<tstamp>元素,该元素一般是声明在最开始执行的<target>元素中,该元素的目的是获取当前系统的时间,例如这里的preprocess。然后在后续的元素中可以直接使用类似于${DSTAMP},${TSTAMP},${TODAY}来表现当前系统时间。
生成的Jar文件名如下:

Java里面做的很多事情,Ant全都可以做,而且更加自动化。
文件系统操作: Ant003-30:00
1、创建和删除目录:
最基本的文件系统操作之一就是创建目录或文件夹。做这项工作的任务名为 mkdir
<mkdir dir="archive/metals/zinc" />
mkdir任务的另一个有用的特性是它的如下能力:在父目录还不存在时创建他们,类似于Java中File#mkdirs()方法一样。
如果目标目录已经存在,mkdir任务不会发出错误消息,而只是假设它的工作已经完成了,从而什么也不去做。
删除目录:
<delete dir="archive/metals/zinc" />
这将删除指定目录连同它包含的所有文件以及子目录。使用file属性而不是dir属性可以指定要删除的单个文件。
2、复制、移动文件和目录:
<copy file="src/Test.java" tofile="src/TestCopy.java" />
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project name="AntTest" basedir="." default="dist"> 3 <!-- 4 <property name="hello" value="hello123"></property> 5 <property name="world" value="world123"></property> 6 7 <target name="init"> 8 <mkdir dir="${hello}"/> 9 <mkdir dir="${world}"/> 10 </target> 11 12 <target name="preprocess" depends="init"></target> 13 <target name="compile" depends="init,preprocess"></target> 14 <target name="package" depends="compile"></target> 15 --> 16 17 <property name="compile" value="compile"></property> 18 <target name="preprocess"> 19 <tstamp></tstamp> 20 <mkdir dir="${compile}"/> 21 </target> 22 <target name="myCompile" depends="preprocess"> 23 <javac srcdir="src" destdir="${compile}"></javac> 24 </target> 25 26 <target name="dist" depends="myCompile"> 27 <jar destfile="package-${DSTAMP}.jar" basedir="${compile}"> 28 <manifest> 29 <attribute name="Built-By" value="${user.name}" /> 30 <attribute name="Main-Class" value="cn.edu.bupt.ant.AntUI" /> 31 </manifest> 32 </jar> 33 <copy file="package-${DSTAMP}.jar" tofile="package-${DSTAMP}-copy.jar"></copy> 34 </target> 35 </project>

<copy>任务的 todir属性可以指定将某个文件copy至指定目录下:
<copy file="src/Test.java" todir="src" />
<?xml version="1.0" encoding="UTF-8"?> <project name="AntTest" basedir="." default="dist"> <!-- <property name="hello" value="hello123"></property> <property name="world" value="world123"></property> <target name="init"> <mkdir dir="${hello}"/> <mkdir dir="${world}"/> </target> <target name="preprocess" depends="init"></target> <target name="compile" depends="init,preprocess"></target> <target name="package" depends="compile"></target> --> <property name="compile" value="compile"></property> <target name="preprocess"> <tstamp></tstamp> <mkdir dir="${compile}"/> </target> <target name="myCompile" depends="preprocess"> <javac srcdir="src" destdir="${compile}"></javac> </target> <target name="dist" depends="myCompile"> <jar destfile="package-${DSTAMP}.jar" basedir="${compile}"> <manifest> <attribute name="Built-By" value="${user.name}" /> <attribute name="Main-Class" value="cn.edu.bupt.ant.AntUI" /> </manifest> </jar> <copy file="package-${DSTAMP}.jar" todir="./hello123"></copy> </target> </project>

todir属性中的正斜杠"/"和反斜杠"\"在各种平台中的转换,Ant会自动帮助你进行处理。
移动文件:<move>
<move file="src/Test.java" tofile="src/TestCopy.java" />
<move>tasck除了可以进行移动操作之外,还可以进行重命名操作.
<?xml version="1.0" encoding="UTF-8"?> <project name="AntTest" basedir="." default="movefile"> <property name="compile" value="compile"></property> <target name="preprocess"> <tstamp></tstamp> <mkdir dir="${compile}"/> </target> <target name="myCompile" depends="preprocess"> <javac srcdir="src" destdir="${compile}"></javac> </target> <target name="dist" depends="myCompile"> <jar destfile="package-${DSTAMP}.jar" basedir="${compile}"> <manifest> <attribute name="Built-By" value="${user.name}" /> <attribute name="Main-Class" value="cn.edu.bupt.ant.AntUI" /> </manifest> </jar> <copy file="package-${DSTAMP}.jar" todir="./hello123"></copy> </target> <target name="movefile" depends="dist"> <!-- 这里的move对当前目录的文件进行move操作,但是源目录和目标目录为同一个目录,因此会进行重命名操作 --> <move file="./hello123/package-${DSTAMP}.jar" tofile="./hello123/package-${DSTAMP}-move.jar"></move> </target> </project>

<move>task的移动文件功能(相当于一个剪切操作):
<target name="movefile"> <mkdir dir="./move"/> <move file="./hello123/package-move.jar" todir="./move"></move> </target>

copy 和 move 均包含 tofile 和 todir两个属性,两个属性不能共存。当使用tofile时,必须指定到具体的文件名;而使用todir时,指定到具体的目录即可,而复制或移动后的文件名与原来的文件名相同。因为这样的功能move就具有了可以重命名文件的功能。
创建和解压缩zip文件: Ant004-01:20
压缩操作:
<zip destfile="output.zip" basedir="output" />
例:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project basedir="." name="AntTest" default="dist"> 3 4 <property name="compiledir" location="./compile" description="编译类文件根目录"></property> 5 <property name="basedir" location="./src" description="源代码根目录"></property> 6 7 <target name="init"> 8 <tstamp></tstamp> 9 </target> 10 11 <target name="compile" depends="init" description="编译"> 12 <mkdir dir="${compiledir}"></mkdir> 13 <javac srcdir="${basedir}" destdir="${compiledir}"></javac> 14 </target> 15 16 <target name="dist" depends="compile" description="生成指定的可运行的Jar文件"> 17 <jar destfile="./jar/package.jar" basedir="${compiledir}"> 18 <manifest> 19 <attribute name="Built-By" value="${user.name}"/> 20 <attribute name="Main-Class" value="cn.edu.bupt.ant.Button"/> 21 </manifest> 22 </jar> 23 </target> 24 25 <target name="move"> 26 <mkdir dir="./move"/> 27 <!-- 移动文件 --> 28 <copyfile dest="./move/package.jar" src="./jar/package.jar"/> 29 </target> 30 31 <target name="compress" depends="compile"> 32 <zip destfile="./zip/package.zip" basedir="${compiledir}"></zip> 33 </target> 34 </project>
说明:上面可以先执行<mkdir dir="./zip" />也可以不执行,两者均可以自动的创建zip目录。

zip中目录结构如下:

解压缩操作:
<unzip src="output.tar.gz" dest="extractDir" />
此外这里可以包括Overwrite属性来控制覆盖行为。默认设置是覆盖与正在被提取的归档文件中的条目相匹配的所有现有文件。
<target name="decompress" depends="compress"> <unzip dest="./dist" src="./zip/package.zip" overwrite="false"></unzip> </target>

Ant对CVS的支持: Ant004-09:00
CVS任务的主要属性是cvsRoot,它是对CVS库的完整引用,包括连接方法和用户详细信息。
格式如下:
[:<method>:][[<user>][:<password>]@]<hostname>[:[<port>]]</path/to/repository>
例如:
:pserver:yangmu:apple:@localhost:c:\cvs
提取是CVS任务的默认操作;其他操作可通过使用command属性来指定。
(具体解释见视频)
<?xml version="1.0" encoding="UTF-8"?> <project basedir="." name="AntTest" default="dist"> <property name="cvs" location=":pserver:yangmu:apple@localhost:c:\cvs" description="csv目录"></property> <property name="cvscheckoutdir" location="E:/mycvs"></property> <target name="init"> <tstamp></tstamp> <mkdir dir="${cvscheckoutdir}"/> </target> <target name="cvs"> <cvs cvsroot="${cvs}" package="chat" command="checkout" dest="${cvscheckoutdir}" /> </target> </project>
替换文件中的标记:
<replace>任务,它执行文件中的查找和替换操作。
token属性指定要查找的字符串,value属性指定一个新的字符串,查找到的标记字符串的所有实例都被替换为这个新的字符串。例如:
<replace file="input.txt" token="old" value="new" />
替换操作将在文件本身之内的适当位置进行。为了提供更详细的输出,可把summary属性设置为true。这将导致该任务输出找到和替换的标记字符串实例的数目。
summary属性值有多个可选值

其中false、no、off三者是相同的意思,on、true、yes三者是相同的意思。
这是Ant的一个特点,很多的布尔类型的属性都是这种多值选项,比较人性化一些。
现创建如下txt文本文件:

然后运行如下<target>
<target name="replace"> <replace file="hello.txt" token="How" value="what" summary="on"></replace> </target>
这时将会将源文件中的所有How替换成为what,运行后如下:


模式匹配 :
可以对目录执行模式匹配。例如:模式src*/*.java将匹配带src前缀的任何目录中的所有Java文件。
还有另外一种模式结构:**,它匹配任意数量的目录。例如,模式**/*.java将匹配当前目录结构下的所有Java文件。即如果当前目录下存在子目录,它还会匹配当前目录下的所有子目录中的.java文件。
因此*/*.java与**/*.java的概念完全不一样,前者仅仅匹配当前目录中所有的子目录中一层的所有.java文件,而后者是匹配当前目录中所有子目录的任意层的.java文件,即包含各种嵌套的子目录。
例如: Ant004-25:00
<target name="patterncopy"> <copy todir="dist"> <fileset dir="src"> <include name="**/*.java"/> </fileset> </copy> </target>
这样将会把src目录中的所有目录层次结构的.java文件连同其目录结构copy至./dist目录结构中。


但是,如果将上面的name="**/*.java" 替换成为 name="*/*.java",则不会在dist中出现任何目录或者文件。在copy指定文件的时候,会带上其所在的所有目录层次,例如上面我仅仅copy.java文件,但是会加上其所在的cn/edu/bupt/ant嵌套目录。
<fieldset>默认情况下包含指定的目录下的所有文件,因此为了仅选择Java文件,我们对模式使用一个include元素。类似的,我们可以对另一个模式添加一个exclude元素,从而潜在的排除include指定的匹配项。甚至可以指定多个include和exclude元素;这样将得到一组文件和目录,它们包含include模式的所有匹配项的并集,但排除了exclude模式的所有匹配项。
使用自定义任务来扩展Ant:
Ant本身提供了足够多的标签供开发者去使用,但是有时候还是无法满足我们的需求,因此我们 可以自定义task来扩展标签,相当于扩展标签。
例如:我们考察一个简单的自定义任务的构造过程。这个任务将对文件中的行执行排序操作,并将排序后的行集写到一个新的文件中。
为了实现一个简单的自定义任务,我们需要做的就是首先扩展 org.apache.tools.ant.Task类,并且重写execute()。
对于大多数任务来说,不管是核心任务还是自定义任务,都需要利用属性来控制他们的行为。对于这个简单的任务,我们需要一个属性来指定排序的文件,需要另一个属性来指定排序内容的输出文件。我们把这两个属性分别叫做file 和 tofile。于此同时,我们需要在自定义类中定义好两个属性,这两个属性与脚本中的两个属性file 和 tofile是对应的。
1> 对于Ant首先需要将Ant.jar文件包含至classpath中.

2> 创建执行任务的Java代码:
package cn.edu.bupt.anttools; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Task; public class FileSorter extends Task { // 类似于Spring ,在配置文件中的相应属性自动的注入当这两个字段中,因此需要提供getter&setter,内部使用了属性编辑器进行了格式转换 private File src; private File dest; // ------------ setter&getter ------------ public File getSrc() { return src; } public void setSrc(File src) { this.src = src; } public File getDest() { return dest; } public void setDest(File dest) { this.dest = dest; } @Override public void execute() throws BuildException { try { BufferedReader srcReader = new BufferedReader(new InputStreamReader(new FileInputStream(this.src))); BufferedWriter destWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(this.dest))); try { String line = null; List<Integer> inputList = new ArrayList<Integer>(); while ((line = srcReader.readLine()) != null) { inputList.add(Integer.valueOf(line)); } Collections.sort(inputList, new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { // TODO Auto-generated method stub return o1 - o2; } }); for (Integer i : inputList) { destWriter.write(i.toString()); destWriter.newLine(); } } finally { destWriter.flush(); srcReader.close(); destWriter.close(); } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
3> 在build.xml文件中定义标签:
<!-- 自定义task标签部分,注意这里的classpath,便于Ant能够找到所指定的.class文件 --> <taskdef name="myfilesorter" classname="cn.edu.bupt.anttools.FileSorter" classpath="./classes"> </taskdef> <!-- 标签的使用 --> <target name="myfilesorter"> <!-- 这里使用了属性编辑器 ,因此需要同名属性src 和 dest--> <myfilesorter src="input.txt" dest="output.txt" /> </target>
这里eclipse中所指定的classpath与Ant中所指定的classpath是完全没有关系的两个概念,因此这里需要指定classpath="./classes"来让Ant找到指定的FileSorter类.
注意这里需要指定.class文件所在的路径,而不是src中的.java文件所在路径.
在<target>中使用task <myfilesorter>时,所使用的属性需要与cn.edu.bupt.anttools.FileSorter带有setter的属性名称相对应,注意大小写.
由于FileSorter中的属性为File类型的对象,而配置文件中全部都是String类型的字符串,所以Ant内部使用了属性编辑器对类型进行转换。
4> 执行:
input.txt

output.txt


浙公网安备 33010602011771号