Gradle 1.12 翻译——第十六章. 使用文件

有关其它已翻译的章节请关注Github上的项目:https://github.com/msdx/gradledoc/tree/1.12,或訪问:http://gradledoc.qiniudn.com/1.12/userguide/userguide.html

本文原创。转载请注明出处:http://blog.csdn.net/maosidiaoxian/article/details/41113353

关于我对Gradle的翻译,以Github上的项目及http://gradledoc.qiniudn.com 上的文档为准。如有发现翻译有误的地方,将首先在以上两个地方更新。

因时间精力问题。博客中发表的译文基本不会同步改动。

第十六章. 使用文件

大多数构建工作都要使用到文件。

Gradle 加入了一些概念和 API 来帮助您实现这一目标。

16.1.
定位文件

你能够使用Project.file()方法来找到一个相对于项目文件夹的文件

演示样例 16.1. 查找文件

build.gradle

// Using a relative path
File configFile = file('src/config.xml') // Using an absolute path
configFile = file(configFile.absolutePath) // Using a File object with a relative path
configFile = file(new File('src/config.xml'))

您能够把不论什么对象传递给file()方法,而它将尝试将其转换为一个绝对路径的File对象。通常情况下。你会传给它一个StringFile的实例。

而所提供的这个对象的tostring()方法的值会作为文件路径。假设这个路径是一个绝对路径,它会用于构构一个File实例。

否则,会通过先计算所提供的路径相对于项目文件夹的相对路径来构造File实例。这个file
()
方法也能够识别URL,比如是file:/some/path.xml

这是把一些用户提供的值转换为一个相对路径的File对象的实用方法。

因为file()方法总是去计算所提供的路径相对于项目文件夹的路径,最好是使用new
File(somePath)
,由于它是一个固定的路径,而不会由于用户执行Gradle的详细工作文件夹而改变。

16.2..文件集合

一个文件集合仅仅是表示一组文件。它通过FileCollection接口来表示。

Gradle
API 中的很多对象都实现了此接口。

比方,依赖配置 就实现了 FileCollection 这一接口。

使用Project.files()方法是获取一个FileCollection实例的当中一个方法。你能够向这种方法传入随意个对象。而它们会被转换为一组 File 对象。这个Files()方法接受不论什么类型的对象作为其參数。

依据16.1
章节 “定位文件”
里对file()方法的描写叙述,它的结果会被计算为相对于项目文件夹的相对路径。你也能够将集合。迭代变量,map和数组传递给files()方法。

它们会被展开,而且内容会转换为 File 实例。

演示样例 16.2. 创建一个文件集合

build.gradle

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 collection
collection.each {File file ->
println file.name
} // Convert the collection to various types
Set 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 collections
def 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 对象而里面的文件会在以后才创建,比方说在一些任务中才创建。

16.3. 文件树

文件树是按层次结构排序的文件集合。比如,文件树可能表示一个文件夹树或
ZIP 文件的内容。它通过FileTree接口表示。

FileTree接口继承自FileCollection,所以你能够用对待文件集合一样的方式来对待文件树。

Gradle
中的几个对象都实现了FileTree接口。比如source
sets

使用Project.fileTree()方法是获取一个FileTree实例的当中一种方法。它将定义一个基文件夹创建FileTree对象。并能够选择加上一些
Ant风格的包括与排除模式。

演示样例 16.5. 创建一个文件树

build.gradle

// Create a file tree with a base directory
FileTree tree = fileTree(dir: 'src/main') // Add include and exclude patterns to the tree
tree.include '**/*.java'
tree.exclude '**/Abstract*' // Create a tree using path
tree = fileTree('src').include('**/*.java') // Create a tree using closure
tree = fileTree('src') {
include '**/*.java'
} // Create a tree using a map
tree = 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 tree
tree.each {File file ->
println file
} // Filter a tree
FileTree filtered = tree.matching {
include 'org/gradle/api/**'
} // Add trees together
FileTree sum = tree + fileTree(dir: 'src/test') // Visit the elements of the tree
tree.visit {element ->
println "$element.relativePath => $element.file"
}

16.4.
使用归档文件的内容作为文件树

您能够使用档案的内容,如 ZIP 或者 TAR 文件,作为一个文件树。你能够通过使用Project.zipTree()Project.tarTree()方法来实现这一过程。这些方法返回一个FileTree实例,您能够像使用不论什么其它文件树或文件集合一样使用它。比如,您能够用它来通过复制内容扩大归档,或把一些档案合并到还有一个归档文件里。

演示样例 16.7. 使用归档文件作为文件树

build.gradle

// Create a ZIP file tree using path
FileTree zip = zipTree('someFile.zip') // Create a TAR file tree using path
FileTree 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'))

16.5.
指定一组输入文件

Gradle 中的很多对象都有一个接受一组输入文件的属性。

比如, JavaCompile任务有一个source属性,定义了要编译的源码文件。你能够使用上面所看到的的files()方法所支持的随意类型的对象设置此属性。这意味着您能够通过如FileString
集合、 FileCollection对象。或甚至是一个闭包来设置此属性。这里有一些样例:

演示样例 16.8. 指定一组文件

build.gradle

// Use a File object to specify the source directory
compile {
source = file('src/main/java')
} // Use a String path to specify the source directory
compile {
source = 'src/main/java'
} // Use a collection to specify multiple source directories
compile {
source = ['src/main/java', '../shared/java']
} // Use a FileCollection (or FileTree in this case) to specify the source files
compile {
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() }
}

16.6.
拷贝文件

你能够使用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.6.1. 重命名文件

演示样例 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.6. 过滤文件

演示样例 16.16. 过滤要复制的文件

build.gradle

import org.apache.tools.ant.filters.FixCrLfFilter
import 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]"
}
}

16.6.3. 使用CopySpec

复制规范用来组织一个层次结构。

一个复制规范继承其目标路径。包括模式,排除模式,复制操作,名称映射和过滤器。

演示样例 16.17. 嵌套的复制规范

build.gradle

task nestedSpecs(type: Copy) {
into 'build/explodedWar'
exclude '**/*staging*'
from('src/dist') {
include '**/*.html'
}
into('libs') {
from configurations.runtime
}
}

16.7.
使用Sync任务

Sync任务继承了Copy任务。

当它运行时,它会将源文件拷贝到目标文件夹中。然后从目标文件夹移除全部不是它复制的文件。

这能够用来做一些事情,比方安装你的应用程序、
创建你的归档文件的exploded副本,或维护项目的依赖项的副本。

这里是一个样例,维护在build/libs文件夹中的项目执行时依赖的副本。

演示样例 16.18. 使用同步任务复制依赖项

build.gradle

task libs(type: Sync) {
from configurations.runtime
into "$buildDir/libs"
}

16.8.
创建归档文件

一个项目能够有你所想要的一样多的 JAR 文件。您也能够将WAR、 ZIP 和TAG文件加入到您的项目。使用各种归档任务能够创建下面的归档文件: ZipTarJarWar,
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 插件对归档任务加入了一些默认值。

假设你愿意,使用归档任务时能够不须要Java插件。您须要提供一些值给附加的属性。

归档任务与Copy任务的工作方式一样,而且实现了同样的CopySpec接口。像使用Copy任务一样,你须要使用from() 的方法指定输入的文件,并能够选择是否通过 into() 方法指定终于在存档中的位置。您能够通过一个复制规范来筛选文件的内容、
重命名文件和进行其它你能够做的事情。

16.8.1. 归档命名

生成的归档的默认名称是projectName-version.type

举个样例:

演示样例 16.20. 创建 ZIP 文件

build.gradle

apply plugin: 'java'

version = 1.0

task 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

它加入了一个名称为myZipZIP归档任务,产生
ZIP 文件 zipProject
1.0.zip

区分归档任务的名称和归档任务生成的归档文件的名称是非常重要的。

归档的默认名称能够通过项目属性 archivesBaseName 来更改。还能够在以后的不论什么时候更改归档文件的名称。

这里有非常多你能够在归档任务中设置的属性。它们在下面的
16.1,"存档任务-命名属性"
中列出。

你能够。例如说,更改归档文件的名称:

演示样例 16.21. 配置归档任务-自己定义归档名称

build.gradle

apply plugin: 'java'
version = 1.0 task 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.0 task 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 baseName-appendix-version-classifier.extension

假设这些属性中的不论什么一个为空,那后面的-不会被加入到该名称中。

生成的归档文件的基本文件名称
archivePath File destinationDir/archiveName 生成的归档文件的绝对路径。
destinationDir File 依赖于归档类型。

JAR包和 WAR包会生成到 project.buildDir/libraries中。ZIP文件和
TAR文件会生成到project.buildDir/distributions中。

存放生成的归档文件的文件夹
baseName String project.name 归档文件的名称中的基本名称部分。
appendix String null 归档文件的名称中的附录部分。
version String project.version 归档文件的名称中的版本号部分。
classifier String null 归档文件的名称中的分类部分。
extension String 依赖于归档的类型,用于TAR文件,能够是下面压缩类型: zipjarwartartgz or tbz2. 归档文件的名称中的扩展名称部分。

16.8.2. 共享多个归档之间的内容

你能够使用Project.copySpec()方法在归档之间共享内容。

你常常会想要公布一个归档文件,这样就可从还有一个项目中使用它。这一过程在
51章。公布文件
中会讲到。

上一篇:学习总结 java Iterator迭代器练习


下一篇:Java经典23种设计模式之创造型模式(一)