2、Ant目标详解及使用Ant的各种任务

利思源
2023-12-01

1、从命令提示符调用Ant可以简单的只需键入单独的ant,如果这样做,ant将使用默认的生成文件;该生成文件中指定的默认目标就是Ant尝试要生成的目标。还可以指定许多命令行选项,后面跟着任意数量的生成目标,Ant将按顺序生成这其中的每个目标,并在此过程中解决所有依赖关系。

2、默认情况下,Ant寻找一个名字为build.xml的文件,因此,如果你的生成文件使用这个名称,就不需要在命令行指定他。当然,有时使用具有其他名称的生成文件更方便,在那样的情况下,你需要对Ant使用 -buildfile <file> 参数 (-f <file> 是其简写形式)

命令行选项:另一个有用的选项是 -D,它用于设置随后可以在生成文件中使用的属性。这对于配置你想要以某种方式开始的生成过程是非常有用的。例如,为了将name属性设置为某个特定的值,你会使用类似下面这样的选项:

    -Dmetal=beryllium

这个功能可用于覆盖生成文件中的初始属性设置,正如前面指出的,属性的值一经设定就不能改变。-D标志在读取生成文件中的任何信息之前设置某个属性;由于生成文件中的指派落在这个初始指派之后,因此它不会改变其值。

3、IDE集成

1)编译源代码

- <javac srcdir="src">

这个标签需找src目录中以.java为扩展名的所有文件,并对它们调用javac编译器,从而在相同的目录中生成类文件。当然,将类文件放在单独的目录结构中通常会更清晰;可以通过添加destdir属性来让Ant做到这点。

其他有用的属性包括:

- classpath:等价于javac的 -classpath选项。
- debug=“true”:指示编译器应该带调试信息编译源文件。

javac任务的一个重要特点在于,它仅编译那些它认为需要编译的源文件。如果某个类文件已经存在,并且对应的源文件自从该类文件生成以来还没有改变过,那么该源文件就不会被重新编译。

javac任务的输出显示了实际被编译的源文件的数目。

这种行为刻画了Ant的许多任务的特点:如果某个任务能够确定所请求的操作不需要执行,那么该操作就会被跳过。

2)创建Jar文件

在编译Java源文件之后,结果类文件通常被打包到一个Jar文件中,这个文件类似zip归档文件。每个Jar文件都包含一个清单文件,它可以指定该Jar文件的属性

下面是Ant中jar任务的一个简单使用例子:
<jar destfile="package.jar" basedir="classes" />

这将创建一个名为package.jar的JAR文件,并把classes目录中的所有文件添加到其中(JAR文件能够包含任意类型的文件,而不只是类文件)。此处没有指定清单文件,因此Ant将提供一个基本的清单文件。

Jar文件中的清单文件:文件名为MANIFEST.MF,其中的内容为:

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.2
Created-By: 1.6.0_13-b03 (Sun Microsystems Inc.)

我们经常看到双击能够运行的JAR文件,现在我们就使用Ant生成这样一个文件。首先编写一个带main方法能够运行的类:

import java.awt.Color;
import java.awt.Dimension;

import javax.swing.JButton;
import javax.swing.JFrame;

public class Test3
{
	public static void main(String[] args)
	{
		JFrame frame = new JFrame("hello Ant");
		
		frame.setSize(new Dimension(200,300));
		frame.setBackground(new Color(200,200,200));
		frame.setAlwaysOnTop(true);
		frame.getContentPane().add(new JButton("Ant"));
		frame.setVisible(true);
		
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
}


然后编写相应的Ant生成文件:

<?xml version="1.0" encoding="UTF-8"?>
<project name="myproject" default="mycompile">
	<property name="compile" value="compile"></property>
	<property name="dist" value="dist"></property>
	<target name="init">
		<mkdir dir="${compile}"/>
	</target>
	<target name="mycompile" depends="init">
		<javac srcdir="src" destdir="${compile}"></javac>
	</target>
	
	<target name="dist" depends="mycompile">
		<jar destfile="${dist}/package.jar" basedir="${compile}">
			<manifest>
				<attribute name="Built-By" value="${user.name}"/>
				<attribute name="Main-Class" value="com.cdtax.test.Test3"/>
			</manifest>
		</jar>
	</target>
</project>

主要就是jar标签的子标签manifest,来指定jar的清单文件的内容,最主要的就是Main-Class,指出双击JAR文件运行的类,这里就是Test3.

最终的清单文件:

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.2
Created-By: 1.6.0_13-b03 (Sun Microsystems Inc.)
Built-By: Administrator
Main-Class: com.cdtax.test.Test3

manifest属性允许指定一个作用该JAR文件的清单的文件。清单文件的内容还可以使用manifest任务在生成文件中指定。这个任务能够向文件系统写入一个清单文件,或者能够实际嵌套在jar之内,以便一次性的创建清单文件和JAR文件。

3)时间戳生成

在生成环境中使用当前时间和日期,以某种方式标记某个生成任务的输出,以便记录它是何时生成的,这经常是可取的。这可能涉及编辑一个文件,以便插入一个字符串来指定日期和时间或将这个信息合并到JAR或zip文件的文件名中。

这种需要是通过简单但是非常有用的tstamp任务来解决的。这个任务通常在某次生成过程开始时调用,比如在一个init目标中。这个任务不需要属性,许多情况下只需<tstamp />就足够了。

tstamp不产生任何输出;相反,它根据当前系统事件和日期设置Ant属性。下面是tstamp设置的一些属性、对每个属性的说明,以及这些属性可被设置到的值得例子。

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

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

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

<?xml version="1.0" encoding="UTF-8"?>
<project name="myproject" default="mycompile">
	<property name="compile" value="compile"></property>
	<property name="dist" value="dist"></property>
	<target name="init">
		<mkdir dir="${compile}"/>
	</target>
	<target name="mycompile" depends="init">
		<javac srcdir="src" destdir="${compile}" includeantruntime="false"></javac>
	</target>
	
	<target name="dist" depends="mycompile">
		<tstamp></tstamp>
		<jar destfile="${dist}/package-${DSTAMP}.jar" basedir="${compile}">
			<manifest>
				<attribute name="Built-By" value="${user.name}"/>
				<attribute name="Main-Class" value="com.cdtax.test.Test3"/>
			</manifest>
		</jar>
	</target>
</project>


注意,如果不加绿色的那一句,运行时总是提示:

Buildfile: D:\workspace10\test\build.xml
init:
mycompile:
    [javac] D:\workspace10\test\build.xml:9: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds
    [javac] Compiling 1 source file to D:\workspace10\test\compile
dist:
      [jar] Building jar: D:\workspace10\test\dist\package-20131216.jar
BUILD SUCCESSFUL
Total time: 1 second

虽然不影响运行结果,还是加上的好。

1.对于includeAntRuntime属性,官方的解释如下:
    Whether to include the Ant run-time libraries in the classpath; defaults to yes, unless build.sysclasspath is set. It is usually best to set this to false so the script's behavior is not sensitive to the environment in which it is run.
2.此警告在较早的ant版本中可能不会出现,当前用的版本是:Apache Ant(TM) version 1.8.2 compiled on December 20 2010。所以此问题跟ant版本有关。

4)文件系统操作

创建和删除目录:最基本的文件系统操作之一就是创建目录或文件夹。做这项工作的任务名为mkdir,<mkdir dir="archivfe/metals/zinc" />

mkdir任务的另一个有用特性是它的如下能力:在父目录还不存在时创建它们

如果目标目录已经存在,mkdir任务不会发出错误消息,而只是假设它的工作已经完成,从而什么也不做

删除目录:<delete dir="archive/metals/zinc" />,这将删除指定的目录连同它包含的所有文件以及子目录。使用file属性而不是dir属性可以指定要删除的单个文件。

 <target name="deletefile">
  <delete file="${dist}/package.jar" />
 </target>

删除pakage.jar单个文件。

复制和移动文件及目录:<copy file="src/Test.java" tofile="src/TestCopy.java" />
还可以使用move来执行重命名操作而不是拷贝文件:<move file="src/Test.java" tofile="src/TestCopy.java" />
另一个常用的文件系统操作时将文件复制或移动到另一个目录:<copy file="src/Test.java" todir="archive" />    ,  <move file="src/Test.java" todir="archive" />

默认情况下,Ant仅输出它执行的移动和复制操作的摘要,包括诸如已移动或复制的文件的数量等信息。如果想看到更详细的信息,包括涉及的文件名称等,可以将verbose属性设置为true

5)创建和解压缩zip文件

<zip destfile="output.zip" basedir="output" /> 将output目录压缩成output.zip文件

<unzip src="output.tar.gz" dest="extractDir" />

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

6)使用CVS

CVS任务的主要属性是cvsRoot,它是对CVS库的完整引用,包括连接方法和用户详细信息。

这个参数的格式如下:

[:method:][[user][:password]@]hostname[:[port]]/path/to/repository

提取是CVS任务的默认操作;其他操作可通过使用command属性来指定

	<property name="cvsRoot" value=":pserver:user1:password1@localhost:c:\cvs"></property>
	<property name="destLocation" value="c:\mycvs"></property>
	<target name="cvs">
		<cvs cvsroot="${cvsRoot}" pakage="chat" command="checkout" dest="${destLocation}"></cvs>
	</target>

7)替换文件中的标记

replace任务,它执行文件中的查找和替换操作。

token属性指定要查找的字符串,value属性指定一个新的字符串,查找到的标记字符串的所有实例都被替换为这个新的字符串,例如:
<replace file="input.txt" token="old" value="new" />

假设有一个文件input.txt,内容:

hello world
how are you
how do you do
how old are you

把how替换为what

<target name="replaceOperate">
	<replace file="input.txt" token="how" value="what"></replace>
</target>

8)模式匹配

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

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

*/*.java  与**/*.java的区别:前者只在当前目录的一级子目录中查找所有java程序,后者则在所有子目录中查找。

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

fileset默认情况下包含指定src目录下的所有文件,因此为了仅选择java文件,我们对模式使用一个include元素。类似地,我们可以对另一个模式添加一个exclude元素,从而潜在地排除include指定的匹配项。甚至可以指定多个include和exclude元素;这样将得到一组文件和目录,它们包含include模式的所有匹配项的并集,但排除了exclude模式的所有匹配项。

默认排除:自动从文件集内容中排除的内置模式列表。该列表包括与名为CVS的目录相匹配的条目,以及以~字符结尾的文件,他们可能是备份文件。通常不想在文件系统操作中包括这类文件和目录,因此排除这些文件是默认行为。然而,如果确实想无例外地选择所有文件和目录,可以将文件集的defaultexcludes属性设置为no。

4、使用自定义任务来扩展ANT

一个简单自定义任务的构造过程,这个任务将对文件中的行执行排序操作,并将排序后的行集写到一个新文件中。

为实现一个简单地自定义任务,需要做的就是扩展org.apache.tools.ant.Task类,并重写execute()方法。

大多数任务,不管是核心任务还是自定义任务,都利用属性来控制它们的行为。对于这个简单任务,我们需要一个属性来指定要排序的文件,需要另一个属性来指定排序内容的输出。我们把这两个属性分别叫做file和tofile

第一步:引入jar包,在下载文件的lib目录下,引入ant.jar文件

第二步:编写类文件,继承Task类,重写execute方法

package com.cdtax.ant.tools.extend;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;

public class FileSorter extends Task
{
	private File srcFile;
	
	private File destFile;

	public File getSrcFile()
	{
		return srcFile;
	}

	public void setSrcFile(File srcFile)
	{
		this.srcFile = srcFile;
	}

	public File getDestFile()
	{
		return destFile;
	}

	public void setDestFile(File destFile)
	{
		this.destFile = destFile;
	}
	
	@Override
	public void execute() throws BuildException
	{
		try
		{
			BufferedReader fromFile = new BufferedReader(new FileReader(srcFile));
			BufferedWriter toFile = new BufferedWriter(new FileWriter(destFile));
			
			List<String> list = new ArrayList<String>();
			String line = fromFile.readLine();
			
			while(line != null)
			{
				list.add(line);
				
				line = fromFile.readLine();
			}
			
			Collections.sort(list);
			
			for(ListIterator<String> li = list.listIterator(); li.hasNext();)
			{
				String str = li.next();
				
				toFile.write(str);
				toFile.newLine();
			}
			
			fromFile.close();
			toFile.close();
			
		}
		catch(Exception ex)
		{
			ex.printStackTrace();
		}
	}
}


注意因为ant使用属性进行赋值,对应到类中,就是使用类的setXXX方法

第三步:在build.xml中使用自定义任务。

<taskdef name="myFileSorter" classname="com.cdtax.ant.tools.extend.FileSorter" classpath="bin"></taskdef>
	<target name="myFileSort">
		<myFileSorter srcFile="input.txt" destFile="output.txt"></myFileSorter>
	</target>


 

 类似资料: