File io Ant:如何为目录中的每个文件执行命令?

File io Ant:如何为目录中的每个文件执行命令?,file-io,ant,build-process,build-automation,File Io,Ant,Build Process,Build Automation,我想从Ant构建文件中为目录中的每个文件执行一个命令。 我正在寻找一个独立于平台的解决方案 我该怎么做 当然,我可以用一些脚本语言编写脚本, 但这将进一步增加项目的依赖性。简短回答 将与嵌套的 Foreach需要 最近ant contrib的更新示例: <target name="foo"> <foreach target="bar" param="theFile"> <fileset dir="${server.src}" casesensitive=

我想从Ant构建文件中为目录中的每个文件执行一个命令。
我正在寻找一个独立于平台的解决方案

我该怎么做

当然,我可以用一些脚本语言编写脚本, 但这将进一步增加项目的依赖性。

简短回答 将
与嵌套的

Foreach需要

最近ant contrib的更新示例:

<target name="foo">
  <foreach target="bar" param="theFile">
    <fileset dir="${server.src}" casesensitive="yes">
      <include name="**/*.java"/>
      <exclude name="**/*Test*"/>
    </fileset>
  </foreach>
</target>

<target name="bar">
  <echo message="${theFile}"/>
</target>


这将使用${theFile}调用目标“bar”,生成当前文件。

ant contrib是邪恶的;编写自定义ant任务

<scriptdef name="bzip2-files" language="javascript">
<element name="fileset" type="fileset"/>
<![CDATA[
  importClass(java.io.File);
  filesets = elements.get("fileset");

  for (i = 0; i < filesets.size(); ++i) {
    fileset = filesets.get(i);
    scanner = fileset.getDirectoryScanner(project);
    scanner.scan();
    files = scanner.getIncludedFiles();
    for( j=0; j < files.length; j++) {

        var basedir  = fileset.getDir(project);
        var filename = files[j];
        var src = new File(basedir, filename);
        var dest= new File(basedir, filename + ".bz2");

        bzip2 = self.project.createTask("bzip2");        
        bzip2.setSrc( src);
        bzip2.setDestfile(dest ); 
        bzip2.execute();
    }
  }
]]>
</scriptdef>

<bzip2-files>
    <fileset id="test" dir="upstream/classpath/jars/development">
            <include name="**/*.jar" />
    </fileset>
</bzip2-files>
ant contrib是邪恶的,因为它试图将ant从声明式样式转换为命令式样式。但是xml是一种糟糕的编程语言

相比之下,定制ant任务允许您使用真实的IDE以真实的语言(Java)编写,您可以在其中编写单元测试以确保您具有所需的行为,然后在构建脚本中明确声明所需的行为

只有当您关心编写可维护的ant脚本时,这种咆哮才有意义。如果您不关心可维护性,请尽一切努力:


联合特遣部队

提出了一种不使用ant contrib的方法

基本上,因为没有以同样的方式扩展(但?) 扩展了,他建议使用(当然也可以在命令行中运行java程序)

这里有一些例子:

  <apply executable="java"> 
    <arg value="-cp"/> 
    <arg pathref="classpath"/> 
    <arg value="-f"/> 
    <srcfile/> 
    <arg line="-o ${output.dir}"/> 

    <fileset dir="${input.dir}" includes="*.txt"/> 
  </apply> 

使用

它对每个文件执行一次命令。通过文件集或任何其他资源指定文件。是内置的;不需要额外的依赖关系;不需要自定义任务实现

也可以只运行一次命令,一次将所有文件作为参数追加。使用“并行”属性切换行为


很抱歉迟到了一年。

下面是使用javascript和ant scriptdef任务实现这一点的方法,因为scriptdef是ant的核心任务,所以您不需要ant contrib就能让这段代码正常工作

<scriptdef name="bzip2-files" language="javascript">
<element name="fileset" type="fileset"/>
<![CDATA[
  importClass(java.io.File);
  filesets = elements.get("fileset");

  for (i = 0; i < filesets.size(); ++i) {
    fileset = filesets.get(i);
    scanner = fileset.getDirectoryScanner(project);
    scanner.scan();
    files = scanner.getIncludedFiles();
    for( j=0; j < files.length; j++) {

        var basedir  = fileset.getDir(project);
        var filename = files[j];
        var src = new File(basedir, filename);
        var dest= new File(basedir, filename + ".bz2");

        bzip2 = self.project.createTask("bzip2");        
        bzip2.setSrc( src);
        bzip2.setDestfile(dest ); 
        bzip2.execute();
    }
  }
]]>
</scriptdef>

<bzip2-files>
    <fileset id="test" dir="upstream/classpath/jars/development">
            <include name="**/*.jar" />
    </fileset>
</bzip2-files>

您可以使用ant contrib任务“for”来迭代任何delimeter分隔的文件列表,默认delimeter为“,”

以下是显示以下内容的示例文件:

<project name="modify-files" default="main" basedir=".">
    <taskdef resource="net/sf/antcontrib/antlib.xml"/>
    <target name="main">
        <for list="FileA,FileB,FileC,FileD,FileE" param="file">
          <sequential>
            <echo>Updating file: @{file}</echo>
            <!-- Do something with file here -->
          </sequential>
        </for>                         
    </target>
</project>

正在更新文件:@{file}

我知道这篇文章确实很老了,但现在经过了一些时间和ant版本,有一种方法可以使用ant的基本功能来实现这一点,我想我应该分享一下

它通过调用嵌套任务(甚至可以调用其他宏)的递归宏定义完成。唯一的约定是使用固定的变量名(这里的元素)


在ant 1.9.1中引入(学分到)
  • 子字符串,非常感谢
  • 内联宏定义元素

  • 我没有设法使分隔符变为variabel,但这可能不是一个主要的缺点。

    按照blak3r的建议做,并像这样定义您的目标类路径

    <taskdef resource="net/sf/antcontrib/antlib.xml">
        <classpath>
            <fileset dir="lib">
              <include name="**/*.jar"/>
            </fileset>
        </classpath>        
    </taskdef>
    
    
    

    where lib是存储jar的地方

    所以,我必须包括一些东西?还是我需要一些外部ant库?我遇到了“问题:无法创建任务或foreach类型”。如果我理解正确,这意味着,foreach是一个未知的关键字。。。这是一项急功近利的任务。所以,你必须安装一些东西。参见此处:该示例来自ant contrib中包含的foreach。这里有一个很好的例子,我将更新这个例子以使其生效。嵌套的fileset元素已被弃用,请使用嵌套的路径instead@dude如果你是对的,我应该用Java编写一个定制的ant任务;)ant contrib真的很邪恶。现在我正处于一个大型的蚂蚁构建项目的中间,它强烈地使用I/S/S/OR和ANTLASK,它真的读起来很恐怖。整个过程看起来就像一个转换的批处理/shell脚本,ant所做的所有依赖项都被ant contrib的大量使用彻底关闭了。如果要保持安装干净,请构建自己的任务:-/@不好意思,我不同意。像任何事情一样,您必须知道何时使用ant contrib最符合您的利益。远离if和var之类的东西,使用ant contrib来避免重新发明轮子。而且,它应该是一种脚本语言,从一开始就是命令式的,而不是声明式的。所以它是邪恶的,谁是邪恶的,也许ant contrib是一个先天的邪恶,但black3r对它的使用似乎是合理的,可以这么说。我在2011年才发现这很有用,所以无论如何还是要感谢它!问题是它只执行外部系统命令。它不会直接做任何烦躁的事情。不清楚最初的问题是不是关于这个。基本上你必须在两种不同的情况下使用or。。。这完全是愚蠢的。这不是非常平台独立的,尽管在最初的问题中它是明确要求的……不幸的是,这会耗尽内存并迅速膨胀。是的,它可能会膨胀堆栈,这取决于您处理的文件数。我用大约66个文件(没有增加内存选项)做得非常成功。但是,如果您没有访问ant contrib的权限,这当然是一个选项,它提供了更多功能(例如并行运行)。这非常有用。上面的示例中引用了变量
    项目
    ,但没有提供先前的定义。最好能说明或澄清这一点。编辑:n/m,发现
    project
    是访问当前项目的预定义变量。对于那些在JDK8或更高版本中尝试这一点的人,请记住,如果JRE加载的脚本引擎是rhino(对于大多数JDK6和7都是这样),而在Nashorn(从8点开始),那么“importClass”可以工作