大多數構建工做都要使用到文件。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章,發佈文件中會講到。