大多数构建工做都要使用到文件。Gradle 添加了一些概念和 API 来帮助您实现这一目标。html
你可使用Project.file()
方法来找到一个相对于项目目录的文件 。java
示例 16.1. 查找文件web
build.gradle
express
// Using a relative pathFile configFile = file('src/config.xml')// Using an absolute pathconfigFile = file(configFile.absolutePath)// Using a File object with a relative pathconfigFile = file(new File('src/config.xml'))
您能够把任何对象传递给file()
方法,而它将尝试将其转换为一个绝对路径的File
对象。一般状况下,你会传给它一个String
或File
的实例。而所提供的这个对象的tostring()
方法的值会做为文件路径。若是这个路径是一个绝对路径,它会用于构构一个File
实例。不然,会经过先计算所提供的路径相对于项目目录的相对路径来构造File
实例。这个file ()
方法也能够识别URL,例如是file:/some/path.xml
。apache
这是把一些用户提供的值转换为一个相对路径的File
对象的有用方法。因为file()
方法老是去计算所提供的路径相对于项目目录的路径,最好是使用new File(somePath)
,由于它是一个固定的路径,而不会由于用户运行Gradle的具体工做目录而改变。api
一个文件集合只是表示一组文件。它经过FileCollection
接口来表示。Gradle API 中的许多对象都实现了此接口。好比,依赖配置 就实现了 FileCollection
这一接口。数组
使用Project.files()
方法是获取一个FileCollection
实例的其中一个方法。你能够向这个方法传入任意个对象,而它们会被转换为一组 File
对象。这个Files()
方法接受任何类型的对象做为其参数。根据16.1 章节 “定位文件”里对file()
方法的描述,它的结果会被计算为相对于项目目录的相对路径。你也能够将集合,迭代变量,map和数组传递给files()
方法。它们会被展开,而且内容会转换为 File
实例。闭包
示例 16.2. 建立一个文件集合app
build.gradle
webapp
FileCollection collection = files('src/file1.txt', new File('src/file2.txt'), ['src/file3.txt', 'src/file4.txt'])
一个文件集合是可迭代的,而且可使用as
操做符转换为其余类型的对象集合。您还可使用+
运算符把两个文件集合相加,或使用-
运算符减去一个文件集合。这里是一些使用文件集合的例子。
示例 16.3. 使用一个文件集合
build.gradle
// Iterate over the files in the collectioncollection.each {File file -> println file.name }// Convert the collection to various typesSet set = collection.files Set set2 = collection as Set List list = collection as List String path = collection.asPath File file = collection.singleFile File file2 = collection as File// Add and subtract collectionsdef union = collection + files('src/file3.txt') def different = collection - files('src/file3.txt')
你也能够向files()
方法传一个闭包或一个Callable
实例。它会在查询集合内容,而且它的返回值被转换为一组文件
实例时被调用。这个闭包或Callable实例的返回值能够是files()
方法所支持的任何类型的对象。这是 “实现” FileCollection
接口的简单方法。
示例 16.4. 实现一个文件集合
build.gradle
task list << { File srcDir // Create a file collection using a closure collection = files { srcDir.listFiles() } srcDir = file('src') println "Contents of $srcDir.name" collection.collect { relativePath(it) }.sort().each { println it } srcDir = file('src2') println "Contents of $srcDir.name" collection.collect { relativePath(it) }.sort().each { println it } }
gradle -q list
的输出结果
> gradle -q list Contents of src src/dir1 src/file1.txt Contents of src2 src2/dir1 src2/dir2
你能够向files()
传入一些其余类型的对象:
FileCollection
它们会被展开,而且内容会被包含在文件集合内。
Task
任务的输出文件会被包含在文件集合内。
TaskOutputs
TaskOutputs 的输出文件会被包含在文件集合内。
要注意的一个地方是,一个文件集合的内容是缓计算的,它只在须要的时候才计算。这意味着您能够,好比建立一个FileCollection
对象而里面的文件会在之后才建立,比方说在一些任务中才建立。
文件树是按层次结构排序的文件集合。例如,文件树可能表示一个目录树或 ZIP 文件的内容。它经过FileTree
接口表示。FileTree
接口继承自FileCollection
,因此你能够用对待文件集合同样的方式来对待文件树。Gradle 中的几个对象都实现了FileTree
接口,例如source sets。
使用Project.fileTree()
方法是获取一个FileTree
实例的其中一种方法。它将定义一个基目录建立FileTree
对象,并能够选择加上一些 Ant风格的包含与排除模式。
示例 16.5. 建立一个文件树
build.gradle
// Create a file tree with a base directoryFileTree tree = fileTree(dir: 'src/main')// Add include and exclude patterns to the treetree.include '**/*.java'tree.exclude '**/Abstract*'// Create a tree using pathtree = fileTree('src').include('**/*.java')// Create a tree using closuretree = fileTree('src') { include '**/*.java'}// Create a tree using a maptree = fileTree(dir: 'src', include: '**/*.java') tree = fileTree(dir: 'src', includes: ['**/*.java', '**/*.xml']) tree = fileTree(dir: 'src', include: '**/*.java', exclude: '**/*test*/**')
你能够像使用一个文件集合的方式同样来使用一个文件树。你也可使用Ant风格的模式来访问文件树的内容或选择一个子树:
示例 16.6. 使用文件树
build.gradle
// Iterate over the contents of a treetree.each {File file -> println file }// Filter a treeFileTree filtered = tree.matching { include 'org/gradle/api/**'}// Add trees togetherFileTree sum = tree + fileTree(dir: 'src/test')// Visit the elements of the treetree.visit {element -> println "$element.relativePath => $element.file"}
您可使用档案的内容,如 ZIP 或者 TAR 文件,做为一个文件树。你能够经过使用Project.zipTree()
或Project.tarTree()
方法来实现这一过程。这些方法返回一个FileTree
实例,您能够像使用任何其余文件树或文件集合同样使用它。例如,您能够用它来经过复制内容扩大归档,或把一些档案合并到另外一个归档文件中。
示例 16.7. 使用归档文件做为文件树
build.gradle
// Create a ZIP file tree using pathFileTree zip = zipTree('someFile.zip')// Create a TAR file tree using pathFileTree tar = tarTree('someFile.tar')//tar tree attempts to guess the compression based on the file extension//however if you must specify the compression explicitly you can:FileTree someTar = tarTree(resources.gzip('someTar.ext'))
Gradle 中的许多对象都有一个接受一组输入文件的属性。例如, JavaCompile
任务有一个source
属性,定义了要编译的源代码文件。你可使用上面所示的files()方法所支持的任意类型的对象设置此属性。这意味着您能够经过如File
、String
、 集合、 FileCollection
对象,或甚至是一个闭包来设置此属性。这里有一些例子:
示例 16.8. 指定一组文件
build.gradle
// Use a File object to specify the source directorycompile { source = file('src/main/java') }// Use a String path to specify the source directorycompile { source = 'src/main/java'}// Use a collection to specify multiple source directoriescompile { source = ['src/main/java', '../shared/java'] }// Use a FileCollection (or FileTree in this case) to specify the source filescompile { source = fileTree(dir: 'src/main/java').matching { include 'org/gradle/api/**' } }// Using a closure to specify the source files.compile { source = { // Use the contents of each zip file in the src dir file('src').listFiles().findAll {it.name.endsWith('.zip')}.collect { zipTree(it) } } }
一般状况下,有一个与属性相同名称的方法,能够追加这个文件集合。再者,这个方法接受files()方法所支持的任何类型的参数。
示例 16.9. 指定一组文件
build.gradle
compile { // Add some source directories use String paths source 'src/main/java', 'src/main/groovy' // Add a source directory using a File object source file('../shared/java') // Add some source directories using a closure source { file('src/test/').listFiles() } }
你可使用Copy
任务来复制文件。复制任务很是灵活,并容许您进行,好比筛选要复制的文件的内容,或映射文件的名称。
若要使用Copy
任务,您必须提供用于复制的源文件和目标目录。您还能够在复制文件的时候指定如何转换文件。你可使用一个复制规范来作这些。一个复制规范经过 CopySpec
接口来表示。Copy
任务实现了此接口。你可使用CopySpec.from()
方法指定源文件,使用CopySpec.into()
方法使用目标目录。
示例 16.10. 使用copy任务复制文件
build.gradle
task copyTask(type: Copy) { from 'src/main/webapp' into 'build/explodedWar'}
from()
方法接受和files()方法同样的任何参数。当参数解析为一个目录时,该目录下的全部文件(不包含目录自己) 都会递归复制到目标目录。当参数解析为一个文件时,该文件会复制到目标目录中。当参数解析为一个不存在的文件时,参数会被忽略。若是参数是一个任务,那么任务的输出文件 (即该任务建立的文件)会被复制,而且该任务会自动添加为Copy
任务的依赖项。into()
方法接受和files()方法同样的任何参数。这里是另外一个示例:
示例 16.11. 指定复制任务的源文件和目标目录
build.gradle
task anotherCopyTask(type: Copy) { // Copy everything under src/main/webapp from 'src/main/webapp' // Copy a single file from 'src/staging/index.html' // Copy the output of a task from copyTask // Copy the output of a task using Task outputs explicitly. from copyTaskWithPatterns.outputs // Copy the contents of a Zip file from zipTree('src/main/assets.zip') // Determine the destination directory later into { getDestDir() } }
您可使用 Ant 风格的包含或排除模式,或使用一个闭包,来选择要复制的文件:
示例 16.12. 选择要复制的文件
build.gradle
task copyTaskWithPatterns(type: Copy) { from 'src/main/webapp' into 'build/explodedWar' include '**/*.html' include '**/*.jsp' exclude { details -> details.file.name.endsWith('.html') && details.file.text.contains('staging') } }
此外,你也可使用Project.copy()
方法来复制文件。它是与任务同样的工做方式,尽管它有一些主要的限制。首先, copy()
不能进行增量操做(见15.9章节,"跳过处于最新状态的任务")。
示例 16.13. 使用没有最新状态检查的 copy() 方法复制文件
build.gradle
task copyMethod << { copy { from 'src/main/webapp' into 'build/explodedWar' include '**/*.html' include '**/*.jsp' } }
第二,当一个任务用做复制源(即做为 from()
的参数)的时候,copy()
方法不能创建任务依赖性,由于它是一个方法,而不是一个任务。所以,若是您在任务的action里面使用copy()
方法,必须显式声明全部的输入和输出以获得正确的行为。
示例 16.14. 使用有最新状态检查的 copy() 方法复制文件
build.gradle
task copyMethodWithExplicitDependencies{ inputs.file copyTask // up-to-date check for inputs, plus add copyTask as dependency outputs.dir 'some-dir' // up-to-date check for outputs doLast{ copy { // Copy the output of copyTask from copyTask into 'some-dir' } } }
在可能的状况下,最好是使用Copy
任务,由于它支持增量构建和任务依赖关系推理,而不须要你额外付出。copy()
方法能够做为一个任务执行的部分来复制文件。即,这个copy()方法旨在用于自定义任务 (见第 57 章,编写自定义任务类)中,须要文件复制做为其一部分功能的时候。在这种状况下,自定义任务应充分声明与复制操做有关的输入/输出。
示例 16.15. 重命名复制的文件
build.gradle
task rename(type: Copy) { from 'src/main/webapp' into 'build/explodedWar' // Use a closure to map the file name rename { String fileName -> fileName.replace('-staging-', '') } // Use a regular expression to map the file name rename '(.+)-staging-(.+)', '$1$2' rename(/(.+)-staging-(.+)/, '$1$2') }
示例 16.16. 过滤要复制的文件
build.gradle
import org.apache.tools.ant.filters.FixCrLfFilterimport org.apache.tools.ant.filters.ReplaceTokens task filter(type: Copy) { from 'src/main/webapp' into 'build/explodedWar' // Substitute property references in files expand(copyright: '2009', version: '2.3.1') expand(project.properties) // Use some of the filters provided by Ant filter(FixCrLfFilter) filter(ReplaceTokens, tokens: [copyright: '2009', version: '2.3.1']) // Use a closure to filter each line filter { String line -> "[$line]" } }
CopySpec
类复制规范用来组织一个层次结构。一个复制规范继承其目标路径,包含模式,排除模式,复制操做,名称映射和过滤器。
示例 16.17. 嵌套的复制规范
build.gradle
task nestedSpecs(type: Copy) { into 'build/explodedWar' exclude '**/*staging*' from('src/dist') { include '**/*.html' } into('libs') { from configurations.runtime } }
Sync
任务Sync
任务继承了Copy
任务。当它执行时,它会将源文件复制到目标目录中,而后从目标目录移除全部不是它复制的文件。这能够用来作一些事情,好比安装你的应用程序、 建立你的归档文件的exploded副本,或维护项目的依赖项的副本。
这里是一个例子,维护在build/libs
目录中的项目运行时依赖的副本。
示例 16.18. 使用同步任务复制依赖项
build.gradle
task libs(type: Sync) { from configurations.runtime into "$buildDir/libs"}
一个项目能够有你所想要的同样多的 JAR 文件。您也能够将WAR、 ZIP 和TAG文件添加到您的项目。使用各类归档任务能够建立如下的归档文件: Zip
, Tar
, Jar
, War
, and Ear
. 他们的工做方式都同样,因此让咱们看看如何建立一个 ZIP 文件。
示例 16.19. 建立一个 ZIP 文件
build.gradle
apply plugin: 'java'task zip(type: Zip) { from 'src/dist' into('libs') { from configurations.runtime } }
Java 插件对归档任务添加了一些默认值。若是你愿意,使用归档任务时能够不须要Java插件。您须要提供一些值给附加的属性。
归档任务与Copy
任务的工做方式同样,而且实现了相同的CopySpec
接口。像使用Copy
任务同样,你须要使用from()
的方法指定输入的文件,并能够选择是否经过 into()
方法指定最终在存档中的位置。您能够经过一个复制规范来筛选文件的内容、 重命名文件和进行其余你能够作的事情。
生成的归档的默认名称是
。举个例子:projectName
-version
.type
示例 16.20. 建立 ZIP 文件
build.gradle
apply plugin: 'java'version = 1.0task myZip(type: Zip) { from 'somedir'} println myZip.archiveName println relativePath(myZip.destinationDir) println relativePath(myZip.archivePath)
gradle -q myZip
的输出结果
> gradle -q myZip zipProject-1.0.zip build/distributions build/distributions/zipProject-1.0.zip
它添加了一个名称为myZip
的ZIP
归档任务,产生 ZIP 文件 zipProject 1.0.zip
。区分归档任务的名称和归档任务生成的归档文件的名称是很重要的。归档的默认名称能够经过项目属性 archivesBaseName
来更改。还能够在之后的任什么时候候更改归档文件的名称。
这里有不少你能够在归档任务中设置的属性。它们在如下的表 16.1,"存档任务-命名属性"中列出。你能够,比方说,更改归档文件的名称:
示例 16.21. 配置归档任务-自定义归档名称
build.gradle
apply plugin: 'java'version = 1.0task myZip(type: Zip) { from 'somedir' baseName = 'customName'} println myZip.archiveName
gradle -q myZip
的输出结果
> gradle -q myZip customName-1.0.zip
您能够进一步自定义存档名称:
示例 16.22. 配置归档任务 - appendix & classifier
build.gradle
apply plugin: 'java'archivesBaseName = 'gradle'version = 1.0task myZip(type: Zip) { appendix = 'wrapper' classifier = 'src' from 'somedir'} println myZip.archiveName
gradle -q myZip
的输出结果
> gradle -q myZip gradle-wrapper-1.0-src.zip
表 16.1. 归档任务-命名属性
属性名称 | 类型 | 默认值 | 描述 |
archiveName |
String |
若是这些属性中的任何一个为空,那后面的 |
生成的归档文件的基本文件名 |
archivePath |
File |
|
生成的归档文件的绝对路径。 |
destinationDir |
File |
依赖于归档类型。JAR包和 WAR包会生成到 中。ZIP文件和 TAR文件会生成到 中。 |
存放生成的归档文件的目录 |
baseName |
String |
project.name |
归档文件的名称中的基本名称部分。 |
appendix |
String |
null |
归档文件的名称中的附录部分。 |
version |
String |
project.version |
归档文件的名称中的版本部分。 |
classifier |
String |
null |
归档文件的名称中的分类部分。 |
extension |
String |
依赖于归档的类型,用于TAR文件,能够是如下压缩类型: zip , jar , war , tar , tgz or tbz2 . |
归档文件的名称中的扩展名称部分。 |
你可使用Project.copySpec()
方法在归档之间共享内容。
你常常会想要发布一个归档文件,这样就可从另外一个项目中使用它。这一过程在第 51章,发布文件中会讲到。