gradle系列——gradle操作文件詳解

我們的疲勞通常不是由於工作,而是由於憂慮,緊張和不快

——戴爾·卡耐基

我們在Android開發中經常會進行文件相關的操作,我們對gradle文件操作做一個說明,以便於將來見到這些命令知道是幹啥的

本地文件

gradle中操作本地文件使用的是 Project.file(java.lang.Object)方法, 通過指定文件的相對路徑或者絕對路徑來進行操作,相對路徑指的是項目的相對路徑,而不是當前文件的相對路徑。

示例代碼如下:

// 使用相對路徑
File configFile = file('src/test.xml')
configFile.createNewFile();

// 使用絕對路徑
configFile = file(/Users/dds/HelloWorld/src/test.xml’)
println(configFile.absolutePath)

// 使用一個文件對象
configFile = file(new File('src/test.xml'))
// 打印文件是否存在
println(configFile.exists())

我們在控制檯執行命令gradle tasks來查看結果

$ gradle tasks
/Users/dds/HelloWorld/src/test.xml
true

文件集合

Gradle中文件集合就是類似於java中的數組,Gradle中使用FileCollection接口表示, 可以使用Project.files(java.lang.Object[])方法來獲得一個文件集合對象 , 所有文件集合都是用到的時候纔會創建

如下代碼 :

FileCollection collection = files('src/test1.txt',
        new File('src/test2.txt'),
        ['src/test3.txt', 'src/test4.txt'])

遍歷操作如下

// 遍歷所有集合
collection.each { File file ->
    println file.name
}

轉換操作如下

// 把文件集合轉換爲Set類型
Set set1 = collection.files
Set set2 = collection as Set
// 把文件集合轉換爲List類型
List list = collection as List
// 把文件集合轉換爲String類型
String path = collection.asPath
// 把文件集合轉換爲File類型
File file1 = collection.singleFile
File file2 = collection as File

增加或者刪除操作

// 添加或者刪除一個集合
def union = collection + files('src/test5.txt')
def different = collection - files('src/test3.txt')

文件樹

文件樹是有層級結構的文件集合,一個文件樹它可以代表一個目錄結構或一 ZIP 壓縮包中的內容結構。文件樹是從文件集合繼承過來的,所以文件樹具有文件集合所有的功能。

我們可以使用Project.fileTree(java.util.Map)方法來創建文件樹對象,還可以使用過慮條件來包含或排除相關文件。示例代碼如下:

// 指定目錄創建文件樹對象
FileTree tree = fileTree(dir: 'src/main')

// 給文件樹對象添加包含指定文件
tree.include '**/*.java'
// 給文件樹對象添加排除指定文件
tree.exclude '**/Abstract*'

// 使用路徑創建文件樹對象,同時指定包含的文件
tree = fileTree('src').include('**/*.java')

// 通過閉包創建文件樹
tree = fileTree('src') {
    include '**/*.java'
}

// 通過map創建文件樹
tree = fileTree(dir: 'src', include: '**/*.java')
tree = fileTree(dir: 'src', includes: ['**/*.java', '**/*.xml'])
tree = fileTree(dir: 'src', include: '**/*.java', exclude: '**/*test*/**')

下面示例展示了文件樹的相關操作:

// 遍歷文件樹的所有文件
tree.each {File file ->
    println file
}

// 過慮生成新的文件樹對象
FileTree filtered = tree.matching {
    include 'org/gradle/api/**'
}

// 使用“+”號合併兩個文件樹,同文件集合的“+”操作一樣
FileTree sum = tree + fileTree(dir: 'src/test')

// 訪問文件樹中各項內容
tree.visit {element ->
    println "$element.relativePath => $element.file"
}

文件拷貝

我們可以使用Copy任務來拷貝文件,通過它可以過慮指定拷貝內容,還能對文件進行重命名操作等。Copy任務必須指定一組需要拷貝的文件和拷貝到的目錄,這裏使用CopySpec.from(java.lang.Object[])方法指定原文件;使用CopySpec.into(java.lang.Object)方法指定目標目錄。示例代碼如下:

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

from()方法接受的參數和文件集合時files()一樣。當參數爲一個目錄時,該目錄下所有的文件都會被拷貝到指定目錄下(目錄自身不會被拷貝);當參數爲一個文件時,該文件會被拷貝到指定目錄;如果參數指定的文件不存在,就會被忽略;當參數爲一個 Zip 壓縮文件,該壓縮文件的內容會被拷貝到指定目錄。

into()方法接受的參數與本地文件時file()一樣。 示例代碼如下:

task copyTask(type: Copy) {
    // 拷貝src/main/webapp目錄下所有的文件
    from 'src/main/webapp'
    // 拷貝單獨的一個文件
    from 'src/staging/index.html'
    // 從Zip壓縮文件中拷貝內容
    from zipTree('src/main/assets.zip')
    // 拷貝到的目標目錄
    into 'build/explodedWar'
}

在拷貝文件的時候還可以添加過慮條件來指定包含或排除的文件,示例如下:

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') }
}

在拷貝文件的時候還可以對文件進行重命名操作,示例如下:

task rename(type: Copy) {
    from 'src/main/webapp'
    into 'build/explodedWar'
    // 使用一個閉包方式重命名文件
    rename { String fileName ->
        fileName.replace('-staging-', '')
    }
    // 使用正則表達示來映射文件名
    rename '(.+)-staging-(.+)', '$1$2'
    rename(/(.+)-staging-(.+)/, '$1$2')
}

在上面的例子中我們都是使用Copy任務來完成拷貝功能的,那麼有沒有另外一種方式呢?答案是肯定的,那就是Project.copy(org.gradle.api.Action)方法。下面示例展示了copy()方法的使用方式:

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

接下來我們再看一種同步拷貝的方式。什麼是同步拷貝呢?就是在拷貝的時候,把原文件拷貝到目標目錄時,會把目標目錄下之前的全部清除,這種方式很適合項目的依賴庫拷貝。示例代碼如下:

task libs(type: Sync) {
    from configurations.runtime
    // 拷貝之前會把$buildDir/libs目錄下所有的清除
    into "$buildDir/libs"
}

最後介紹一種很常用也很特別的拷貝方式:嵌套形式的拷貝。

task nestedSpecs(type: Copy) {
    into 'build/explodedWar'
    exclude '**/*staging*'
    from('src/dist') {
        include '**/*.html'
    }
    // 將運行時的依賴庫拷貝到libs目錄下
    into('libs') {
        from configurations.runtime
    }
}

歸檔文件

通常一個項目會有很多的 Jar 包,我們希望把項目打包成一個 WAR,ZIP 或 TAR 包進行發佈,這時我們就可以使用ZipTarJarWarEar任務來實現,不過它們的用法都一樣,所以在這裏我只介紹Zip任務的示例。

首先,創建一個 Zip 壓縮文件,如下代碼所示:

apply plugin: 'java'

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

其次,可以指定生成的 Zip 壓縮文件名稱,示例如下:

apply plugin: 'java'
version = 1.0

task myZip(type: Zip) {
    from 'src/dist'
    baseName = 'myGame'
}

println myZip.archiveName

執行命令gradle -q myZip,輸出結果爲:

> gradle -q myZip
myGame-1.0.zip

最後,我們可以使用Project.zipTree(java.lang.Object)Project.tarTree(java.lang.Object)方法來創建訪問 Zip 壓縮包的文件樹對象,示例代碼如下:

// 使用zipTree
FileTree zip = zipTree('someFile.zip')
// 使用tarTree
FileTree tar = tarTree('someFile.tar')

參考鏈接

Gradle相關係列

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章