第十六章. 使用文件

Chapter 16. Working With Files

大多数构建工作都需要使用到文件,Gradle 添加了一些概念和 API 来帮助你实现这一点。
Most builds work with files. Gradle adds some concepts and APIs to help you achieve this.

16.1. 查找文件

16.1. Locating files

你可以使用Project.file()方法来找到相对于项目目录的文件。
You can locate a file relative to the project directory using the Project.file() method.

示例 16.1. 查找文件 - Example 16.1. Locating files

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实例给它。如果这个路径是一个绝对路径,它会被用来构造一个文件实例。否则,会通过将项目目录的路径添加到所提供的路径的前面来构建File实例。该file()方法也可以识别URL,如file:/some/path.xml
You can pass any object to the file() method, and it will attempt to convert the value to an absolute File object. Usually, you would pass it a String or File instance. If this path is an absolute path, it is used to construct a File instance. Otherwise, a File instance is constructed by prepending the project directory path to the supplied path. The file() method also understands URLs, such as file:/some/path.xml.

这是把一些用户提供的值转换为一个相对路径的File对象的有用方法。由于file()方法总是去计算所提供的路径相对于项目目录的路径,最好是使用new File(somePath),因为它是一个固定的路径,而不是会因为用户运行Gradle的具体工作目录而改变的当前目录。
Using this method is a useful way to convert some user provided value into an absolute File. It is preferable to using new File(somePath), as file() always evaluates the supplied path relative to the project directory, which is fixed, rather than the current working directory, which can change depending on how the user runs Gradle.

16.2. 文件集合

16.2. File collections

一个文件集合只是一组文件,它通过FileCollection接口来表示。 Gradle API中的许多对象都实现了这个接口。比如,依dependency configurations就实现了FileCollection这一接口。
A file collection is simply a set of files. It is represented by the FileCollection interface. Many objects in the Gradle API implement this interface. For example, dependency configurations implement FileCollection.

使用Project.files()方法是获取方式FileCollection实例的一种方式。你可以传任意个对象给这个方法,它们会被转换为一组File对象。这个files()方法接受任何类型的对象作为其参数。如第16.1节,“查找文件”中对file()方法的描述,它们会被计算为相对于项目目录的路径。你还可以将集合,可迭代类型,map和数组传给files()方法。它们会被展开,并且里面的内容会被转换为File实例。
One way to obtain a FileCollection instance is to use the Project.files() method. You can pass this method any number of objects, which are then converted into a set of File objects. The files() method accepts any type of object as its parameters. These are evaluated relative to the project directory, as per the file() method, described in Section 16.1, “Locating files”. You can also pass collections, iterables, maps and arrays to the files() method. These are flattened and the contents converted to File instances.

示例 16.2. 创建文件集合 - Example 16.2. Creating a file collection

build.gradle

FileCollection collection = files('src/file1.txt', new File('src/file2.txt'), ['src/file3.txt', 'src/file4.txt'])

一个文件集合是可迭代的,可以使用as操作符把它转换为多个其他类型。你也可以使用+运算符把两个文件集合加到一起,或使用-运算符从另一个文件集中减去另一个文件集合。以下是操作文件集合的一些示例。
A file collection is iterable, and can be converted to a number of other types using the as operator. You can also add 2 file collections together using the + operator, or subtract one file collection from another using the - operator. Here are some examples of what you can do with a file collection.

示例 16.3. 使用文件集合 - Example 16.3. Using a file collection

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实例。它会在查询集合的内容时被调用,并将其返回值转换为一组File实例。返回值可以是files()方法所支持的任何类型的对象。这是一个“实现”FileCollection接口的简单方法。
You can also pass the files() method a closure or a Callable instance. This is called when the contents of the collection are queried, and its return value is converted to a set of File instances. The return value can be an object of any of the types supported by the files() method. This is a simple way to 'implement' the FileCollection interface.

示例 16.4. 实现一个文件集合 - Example 16.4. Implementing a file collection

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的输出结果
Output of gradle -q list

> gradle -q list
Contents of src
src/dir1
src/file1.txt
Contents of src2
src2/dir1
src2/dir2

你可以向files()传入以下一些其他类型的对象:
Some other types of things you can pass to files():

FileCollection

它们会被展开,并且内容包含在文件集合中。
These are flattened and the contents included in the file collection.

Task

任务的输出文件会被包含在文件集合中。
The output files of the task are included in the file collection.

TaskOutputs

TaskOutputs 的输出文件会被包含在文件集合中。
The output files of the TaskOutputs are included in the file collection.

要注意的一个地方是,一个文件集合的内容是懒评估的,它只在需要的时候才计算。这意味着你可以创建一个FileCollection 对象来表示一些会在以后才创建的文件,比方说在一些任务中。
It is important to note that the content of a file collection is evaluated lazily, when it is needed. This means you can, for example, create a FileCollection that represents files which will be created in the future by, say, some task.

16.3. 文件树

16.3. File trees

一个文件树是一个按层次结构排列的文件集合。 例如,文件树可能表示一个目录树或ZIP 文件的内容。它通过FileTree 接口来表示。FileTree 接口继承自 FileCollection,因此你可以像处理文件集一样来处理文件树。Gradle中的几个对象都实现了 FileTree 接口,如源码集
A file tree is a collection of files arranged in a hierarchy. For example, a file tree might represent a directory tree or the contents of a ZIP file. It is represented by the FileTree interface. The FileTree interface extends FileCollection, so you can treat a file tree exactly the same way as you would a file collection. Several objects in Gradle implement the FileTree interface, such as source sets.

获取 FileTree 实例的其中一种方式是使用Project.fileTree() 方法。它会创建一个FileTree ,使用一个基本目录来定义,并且可以选择一些Ant风格的包含和排除模式。
One way to obtain a FileTree instance is to use the Project.fileTree() method. This creates a FileTree defined with a base directory, and optionally some Ant-style include and exclude patterns.

示例 16.5. 创建一个文件树 - Example 16.5. Creating a file tree

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风格的模式选择一个子树:
You use a file tree in the same way you use a file collection. You can also visit the contents of the tree, and select a sub-tree using Ant-style patterns:

示例 16.6. 使用文件树 - Example 16.6. Using a file tree

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. 使用归档的内容作为文件树

16.4. Using the contents of an archive as a file tree

你可以通过使用Project.zipTree()Project.tarTree()方法,将档案(如ZIP或TAR文件)的内容用作文件树。这些方法会返回一个 FileTree实例,它可以像其他任何文件树或文件集一样去使用。例如,你可以用它来通过复制内容扩展归档,或者将某些归档合并到另一个归档文件中。
You can use the contents of an archive, such as a ZIP or TAR file, as a file tree. You do this using the Project.zipTree() and Project.tarTree() methods. These methods return a FileTree instance which you can use like any other file tree or file collection. For example, you can use it to expand the archive by copying the contents, or to merge some archives into another.

示例 16.7. 使用归档文件作为文件树 - Example 16.7. Using an archive as a file tree

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. 指定一组输入文件

16.5. Specifying a set of input files

Gradle中的许多对象都有接受一组输入文件的属性。例如, JavaCompile任务有一个source属性,它定义了要编译的源文件。你可以上面所示的files()方法所支持的任何类型来设置此属性的值。这意味着,你可以通过如FileString,集合, FileCollection,甚至是闭包来设置该属性。这里有些例子:
Many objects in Gradle have properties which accept a set of input files. For example, the JavaCompile task has a source property, which defines the source files to compile. You can set the value of this property using any of the types supported by the files() method, which was shown above. This means you can set the property using, for example, a File, String, collection, FileCollection or even a closure. Here are some examples:

示例 16.8. 指定一组文件 - Example 16.8. Specifying a set of files

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()方法所支持的任何类型。
Usually, there is a method with the same name as the property, which appends to the set of files. Again, this method accepts any of the types supported by the files() method.

示例 16.9. 指定一组文件 - Example 16.9. Specifying a set of files

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. 复制文件

16.6. Copying files

你可以使用Copy任务来复制文件。复制任务非常灵活,并允许你在复制时过滤文件的内容,以及映射到文件名中。
You can use the Copy task to copy files. The copy task is very flexible, and allows you to, for example, filter the contents of the files as they are copied, and map to the file names.

要使用Copy任务,你必须提供一组要复制的源文件,以及复制过去的目标目录。你还可以指定在复制文件时如何转换文件。你可以使用一个复制规范。复制规范通过CopySpec接口来表示。Copy任务实现了这个接口。你可以使用CopySpec.from()方法指定源文件。指定目标目录则是使用CopySpec.into()方法。
To use the Copy task, you must provide a set of source files to copy, and a destination directory to copy the files to. You may also specify how to transform the files as they are copied. You do all this using a copy spec. A copy spec is represented by the CopySpec interface. The Copy task implements this interface. You specify the source files using the CopySpec.from() method. To specify the destination directory, use the CopySpec.into() method.

实施例16.10. 使用复制任务复制文件 - Example 16.10. Copying files using the copy task

build.gradle

task copyTask(type: Copy) {
    from 'src/main/webapp'
    into 'build/explodedWar'
}

from()方法接受和files()方法一样的参数。当参数解析为目录时,该目录下的所有内容(除了该目录本身)将递归复制到目标目录中。当参数解析为文件时,该文件将被复制到目标目录中。当参数解析为不存在的文件时,该参数将被忽略。如果参数是一个任务,则复制任务的输出文件(即任务创建的文件),并将任务自动添加为Copy任务的依赖项。该into()接受和file()方法一样的参数。这是另一个例子:
The from() method accepts any of the arguments that the files() method does. When an argument resolves to a directory, everything under that directory (but not the directory itself) is recursively copied into the destination directory. When an argument resolves to a file, that file is copied into the destination directory. When an argument resolves to a non-existing file, that argument is ignored. If the argument is a task, the output files (i.e. the files the task creates) of the task are copied and the task is automatically added as a dependency of the Copy task. The into() accepts any of the arguments that the file() method does. Here is another example:

示例 16.11. 指定复制任务的源文件和目标目录 - Example 16.11. Specifying copy task source files and destination directory

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 风格的包含或排除模式,或是闭包,来选择要复制的文件:
You can select the files to copy using Ant-style include or exclude patterns, or using a closure:

示例 16.12. 选择要复制的文件 - Example 16.12. Selecting the files to copy

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节,“跳过最新的任务”》)。
You can also use the Project.copy() method to copy files. It works the same way as the task with some major limitations though. First, the copy() is not incremental (see Section 15.9, “Skipping tasks that are up-to-date”).

例16.13. 使用没有最新状态检查的copy()方法复制文件 - Example 16.13. Copying files using the copy() method without up-to-date check

build.gradle

task copyMethod << {
    copy {
        from 'src/main/webapp'
        into 'build/explodedWar'
        include '**/*.html'
        include '**/*.jsp'
    }
}

其次,当一个任务用作复制源(即作为from()的一个参数)时,copy()方法不能满足任务依赖。因为它是一个方法,而不是一个任务。因此,如果你正在使用copy()方法作为任务操作的一部分,就必须显式声明所有的输入和输出才能得到正确的行为。
Secondly, the copy() method can not honor task dependencies when a task is used as a copy source (i.e. as an argument to from()) because it's a method and not a task. As such, if you are using the copy() method as part of a task action, you must explicitly declare all inputs and outputs in order to get the correct behavior.

例16.14. 使用有最新状态检查的copy()方法复制文件 - Example 16.14. Copying files using the copy() method with up-to-date check

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() 方法可以作为一个任务的实现的 一部分 来复制文件。也就是说,这个复制方法旨在用于自定义任务(《第五十七章,编写自定义任务类)中,需要把文件复制作为其中一部分功能的时候。在这种情况下,自定义任务应充分声明与复制操作相关的输入和输出。
It is preferable to use the Copy task wherever possible, as it support incremental building and task dependency inference without any extra effort on your part. The copy() method can be used to copy files as part of a task's implementation. That is, the copy method is intended to be used by custom tasks (see Chapter 57, Writing Custom Task Classes) that need to copy files as part of their function. In such a scenario, the custom task should sufficiently declare the inputs/outputs relevant to the copy action.

16.6.1. 重命名文件

16.6.1. Renaming files

示例 16.15. 重命名复制的文件 - Example 16.15. Renaming files as they are copied

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.2 过滤文件

16.6.2. Filtering files

示例 16.16. 在复制时过滤文件 - Example 16.16. Filtering files as they are copied

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.6.3. Using the CopySpec class

复制规范用于形成一个层次结构。一个复制规范继承其目标路径、包含模式、排除模式、复制操作、名称映射和过滤器。
Copy specs form a hierarchy. A copy spec inherits its destination path, include patterns, exclude patterns, copy actions, name mappings and filters.

示例 16.17. 嵌套的复制规范 - Example 16.17. Nested copy specs

build.gradle

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

16.7. 使用Sync任务

16.7. Using the Sync task

Sync 任务扩展了 Copy 任务。当它执行时,它会将源文件复制到目标目录中,然后从目标目录中删除它没有复制的所有文件。这可以用于执行诸如安装应用程序,创建归档文件的分解(解压)副本,或维护项目依赖的副本等。
The Sync task extends the Copy task. When it executes, it copies the source files into the destination directory, and then removes any files from the destination directory which it did not copy. This can be useful for doing things such as installing your application, creating an exploded copy of your archives, or maintaining a copy of the project's dependencies.

下面是一个例子,维护在build/libs目录中的项目运行时依赖的副本。
Here is an example which maintains a copy of the project's runtime dependencies in the build/libs directory.

示例 16.18. 使用同步任务复制依赖项 - Example 16.18. Using the Sync task to copy dependencies

build.gradle

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

16.8. 创建归档文件

16.8. Creating archives

一个项目可以有尽可能多的 JAR 文件。你也可以将 WAR,ZIP 和 TAR 文件添加到你的项目中。这些归档文件是通过以下这些不同的归档任务来创建的: ZipTarJarWarEar。它们的使用方式相同,所以让我们来看看如何创建一个 ZIP 文件。
A project can have as many as JAR archives as you want. You can also add WAR, ZIP and TAR archives to your project. Archives are created using the various archive tasks: Zip, Tar, Jar, War, and Ear. They all work the same way, so let's look at how you create a ZIP file.

示例 16.19. 创建一个 ZIP 文件 - Example 16.19. Creating a ZIP archive

build.gradle

apply plugin: 'java'

task zip(type: Zip) {
    from 'src/dist'
    into('libs') {
        from configurations.runtime
    }
}

为什么要用 Java 插件?

Java 插件为归档任务添加了一些默认值。如果你愿意,使用归档任务时你也可以不使用 Java 插件。你将需要提供一些附加属性的值。
The Java plugin adds a number of default values for the archive tasks. You can use the archive tasks without using the Java plugin, if you like. You will need to provide values for some additional properties.

Why are you using the Java plugin?

归档任务与 Copy 任务的使用方式完全一样,并且实现了同样的 CopySpec 接口。像使用 Copy 任务一样,你需要使用 from() 方法指定输入文件,并且可以选择使用 into() 方法来指定它们在归档中结束的位置。你可以过滤文件内容,重命名文件以及进行通过复制规范可以做的其他事情。
The archive tasks all work exactly the same way as the Copy task, and implement the same CopySpec interface. As with the Copy task, you specify the input files using the from() method, and can optionally specify where they end up in the archive using the into() method. You can filter the contents of file, rename files, and all the other things you can do with a copy spec.

16.8.1. 归档命名

16.8.1. Archive naming

生成的归档的默认名称是projectName-version.type。举个例子:
The default name for a generated archive is projectName-version.type For example:

示例 16.20. 创建 ZIP 文件 - Example 16.20. Creation of ZIP archive

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 的输出结果
Output of 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项目属性来修改,也可以在之后的任何时候更改归档文件的名称。
This adds a Zip archive task with the name myZip which produces ZIP file zipProject-1.0.zip. It is important to distinguish between the name of the archive task and the name of the archive generated by the archive task. The default name for archives can be changed with the archivesBaseName project property. The name of the archive can also be changed at any time later on.

你可以在归档任务上设置很多属性。它们在表16.1“存档任务 - 命名属性”中有列出。例如,你可以更改归档的名称:
There are a number of properties which you can set on an archive task. These are listed below in Table 16.1, “Archive tasks - naming properties”. You can, for example, change the name of the archive:

示例 16.21. 配置归档任务-自定义归档名称 - Example 16.21. Configuration of archive task - custom archive name

build.gradle

apply plugin: 'java'
version = 1.0

task myZip(type: Zip) {
    from 'somedir'
    baseName = 'customName'
}

println myZip.archiveName

gradle -q myZip 的输出结果
Output of gradle -q myZip

> gradle -q myZip
customName-1.0.zip

你也可以进一步自定义存档名称:
You can further customize the archive names:

示例 16.22. 配置归档任务 - appendix & classifier - Example 16.22. Configuration of archive task - 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 的输出结果
Output of gradle -q myZip

> gradle -q myZip
gradle-wrapper-1.0-src.zip

表 16.1. 归档任务-命名属性 - Table 16.1. Archive tasks - naming properties

属性名称
Property name
类型
Type
默认值
Default value
描述
Description
archiveName String baseName-appendix-version-classifier.extension

如果这些属性中的任何一个为空,那其跟随的-不会被添加到该名称中。


baseName-appendix-version-classifier.extension

If any of these properties is empty the trailing - is not added to the name.

生成的归档文件的基本文件名
The base file name of the generated archive
archivePath File destinationDir/archiveName 生成的归档文件的绝对路径。
The absolute path of the generated archive.
destinationDir File 依赖于存档类型。 JAR 和 WAR 会生成到project.buildDir/libraries中。 ZIP 和 TAR 则会生成到project.buildDir/distributions中。
Depends on the archive type. JARs and WARs are generated into project.buildDir/libraries. ZIPs and TARs are generated into project.buildDir/distributions.
存放生成的归档文件的目录
The directory to generate the archive into
baseName String project.name 归档文件名称中的基本名称部分。
The base name portion of the archive file name.
appendix String null 归档文件名称中的附录部分。
The appendix portion of the archive file name.
version String project.version 归档文件名称中的版本部分。
The version portion of the archive file name.
classifier String null 归档文件名称中的分类部分。
The classifier portion of the archive file name,
extension String 依赖于归档类型,并且对于TAR文件,可以是以下压缩类型:zip, jar, war, tar, tgztbz2
Depends on the archive type, and for TAR files, the compression type as well: zip, jar, war, tar, tgz or tbz2.
归档文件名称中的扩展名称部分。
The extension of the archive file name.

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

16.8.2. Sharing content between multiple archives

你可以使用Project.copySpec()方法来共享归档之间的内容。
You can use the Project.copySpec() method to share content between archives.

通常你会想要发布一个档案,这样就可以在另一个项目中使用它。这个过程将在《第五十一章, 发布工件》中讲到。
Often you will want to publish an archive, so that it is usable from another project. This process is described in Chapter 51, Publishing artifacts