在Android工程的編譯和構(gòu)建過程中蓄坏,絕大多數(shù)的工作都涉及到了Gradle相關(guān)的文件操作究履。
文件對(duì)象
在工程目錄下策州,我們可以通過File
的構(gòu)造方法來快速定位一個(gè)文件并創(chuàng)建相應(yīng)的File
對(duì)象:
// 傳入文件的相對(duì)路徑
File configFile = new File('src/config.xml')
// 傳入文件的絕對(duì)路徑
configFile = new File(configFile.absolutePath)
// 通過相對(duì)路徑構(gòu)建一個(gè) java.nio.file.Path 對(duì)象并傳入
configFile = new File(Paths.get('src', 'config.xml'))
// 讀取property變量構(gòu)建 java.nio.file.Path 對(duì)象并傳入
configFile = new File(Paths.get(System.getProperty('user.home')).resolve('global-config.xml'))
之所以推薦用new File()的方式來創(chuàng)建對(duì)應(yīng)文件的對(duì)象而非 Project.file(java.lang.Object)
方法麻昼,主要是因?yàn)?file()方法總是把所傳入的路徑當(dāng)作以當(dāng)前工程目錄的相對(duì)路徑來進(jìn)行解析宵统,而不是當(dāng)前工作目錄。
文件集合
文件集合FileCollection
這個(gè)接口描述了針對(duì)一組文件的操作和屬性拳缠。在Gradle中,許多類都繼承了這一接口贸弥,例如依賴配置對(duì)象dependency configurations .
與創(chuàng)建File對(duì)象不同窟坐,創(chuàng)建FileCollection對(duì)象的唯一方式是通過 Project.files(java.lang.Object[])
方法,該方法的入?yún)?shù)目是任意多個(gè)绵疲,類型也可以是表示相對(duì)路徑的字符串哲鸳,F(xiàn)ile對(duì)象,甚至是集合盔憨,數(shù)組等徙菠。
FileCollection collection = files('src/file1.txt',
new File('src/file2.txt'),
['src/file3.txt', 'src/file4.txt'],
Paths.get('src', 'file5.txt'))
對(duì)于一個(gè)FileCollection對(duì)象,我們可以對(duì)它進(jìn)行各種操作:
// 遍歷文件集合
collection.each { File file ->
println file.name
}
// 將FileCollection對(duì)象轉(zhuǎn)換為其他類型
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
// 對(duì)FileCollection進(jìn)行加減操作
def union = collection + files('src/file3.txt')
def different = collection - files('src/file3.txt')
files()方法也可以接受closure或者Callable對(duì)象作為入?yún)⒂粞遥?dāng)FileCollection中文件內(nèi)容被請(qǐng)求時(shí)closure或Callable會(huì)被回調(diào)婿奔,并轉(zhuǎn)換為一個(gè)File對(duì)象的Set返回。
task list {
doLast {
File srcDir
// 使用closure創(chuàng)建一個(gè)FileCollection對(duì)象
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 }
}
}
File Trees
接口FileTree
是用于描述一個(gè)樹狀結(jié)構(gòu)文件集合的對(duì)象问慎,它不僅可以表示一個(gè)目錄下的文件結(jié)構(gòu)萍摊,還可以描述一個(gè)zip文件中內(nèi)容。
通過Project對(duì)象的fileTree方法如叼,我們可以創(chuàng)建一個(gè)目錄的FileTree對(duì)象冰木。
//創(chuàng)建以src/main為根目錄的FileTree
FileTree tree = fileTree(dir: 'src/main')
// 為FileTree添加include和exclude規(guī)則
tree.include '**/*.java'
tree.exclude '**/Abstract*'
// 使用路徑創(chuàng)建FileTree
tree = fileTree('src').include('**/*.java')
// 使用closure創(chuàng)建FileTree
tree = fileTree('src') {
include '**/*.java'
}
//使用map創(chuàng)建FileTree
tree = fileTree(dir: 'src', include: '**/*.java')
tree = fileTree(dir: 'src', includes: ['**/*.java', '**/*.xml'])
tree = fileTree(dir: 'src', include: '**/*.java', exclude: '**/*test*/**')
由于使用FileTree繼承了FileCollection接口,所以也可以向操作FileCollection那樣操作FileTree笼恰。
// 遍歷
tree.each {File file ->
println file
}
//根據(jù)規(guī)則過濾
FileTree filtered = tree.matching {
include 'org/gradle/api/**'
}
// 合并兩棵FileTree
FileTree sum = tree + fileTree(dir: 'src/test')
// 訪問樹結(jié)構(gòu)的每個(gè)結(jié)點(diǎn)
tree.visit {element ->
println "$element.relativePath => $element.file"
}
上面提到踊沸,我們可以把例如zip或tar的壓縮文件當(dāng)做FileTree對(duì)象來處理。通過Project的zipTree和tarTree文件社证,我們可以根據(jù)zip文件或tar文件創(chuàng)建出對(duì)應(yīng)的FileTree對(duì)象逼龟。
FileTree zip = zipTree('someFile.zip')
FileTree tar = tarTree('someFile.tar')
復(fù)制文件
通過 Copy
Task,我們可以方便靈活地進(jìn)行文件的copy操作追葡。在copy的過程中审轮,我們還可以進(jìn)行文件的重命名肥哎,過濾等操作,這都得益于Copy Task繼承了CopySpec
接口來讓我們指定所要進(jìn)行的操作疾渣。
task anotherCopyTask(type: Copy) {
//指定所要copy的源文件/源目錄
// copy 目錄src/main/webapp下所有文件
from 'src/main/webapp'
// Copy 單個(gè)文件
from 'src/staging/index.html'
// Copy copyTask的輸出作為源文件
from copyTask
// Copy TaskWithPatterns.outputs
from copyTaskWithPatterns.outputs
// Copy Zip 文件中的內(nèi)容
from zipTree('src/main/assets.zip')
// 指定copy操作的輸出目錄
into { getDestDir() }
//通過正則表達(dá)式或者closure來指定copy過程中包含或排除的文件
include '**/*.html'
include '**/*.jsp'
exclude { details -> details.file.name.endsWith('.html') &&
details.file.text.contains('staging') }
}
如果copy任務(wù)簡(jiǎn)單篡诽,也可以使用Project.copy(org.gradle.api.Action)
方法來進(jìn)行文件copy。
task copyMethod {
doLast {
copy {
from 'src/main/webapp'
into 'build/explodedWar'
include '**/*.html'
include '**/*.jsp'
}
}
}
在文件copy過程中榴捡,我們可以遍歷所要操作的文件杈女,對(duì)文件本身進(jìn)行處理和操作。
import org.apache.tools.ant.filters.FixCrLfFilter
import org.apache.tools.ant.filters.ReplaceTokens
task rename(type: Copy) {
from 'src/main/webapp'
into 'build/explodedWar'
// 使用rename函數(shù)接收 closure來修改文件名
rename { String fileName ->
fileName.replace('-staging-', '')
}
// 使用正則表達(dá)式來重命名
rename '(.+)-staging-(.+)', '$1$2'
rename(/(.+)-staging-(.+)/, '$1$2')
}
//在copy過程中也可以用filter對(duì)文件內(nèi)容進(jìn)行處理
// 分別替換文件中copyright和version的值為'2009'吊圾,'2.3.1
// 用properties的鍵值對(duì)進(jìn)行替換
expand(copyright: '2009', version: '2.3.1')
expand(project.properties)
// filter可以接受FilterReader實(shí)例類對(duì)文件內(nèi)容進(jìn)行操作
filter(FixCrLfFilter)
filter(ReplaceTokens, tokens: [copyright: '2009', version: '2.3.1'])
// 使用 closure 逐行過濾處理文件內(nèi)容
filter { String line ->
"[$line]"
}
filter { String line ->
line.startsWith('-') ? null : line
}
filteringCharset = 'UTF-8'
文件下載
利用插件de.undercouch.download
达椰,我們可以完成文件下載的相關(guān)任務(wù),具體引入和使用方式參見:
執(zhí)行腳本命令
通過Exec
task项乒,我們讓gradle腳本來執(zhí)行命令行腳本或命令啰劲。
task stopTomcat(type:Exec) {
// 工作目錄
workingDir '../tomcat/bin'
/ /執(zhí)行 ./stop.sh 腳本
commandLine './stop.sh'
// 存儲(chǔ)命令行打印的結(jié)果
standardOutput = new ByteArrayOutputStream()
// 通過stopTomcat.output() 即可獲得輸出
ext.output = {
return standardOutput.toString()
}
}