Gradle 文件操作

在Android工程的编译和构建过程中,绝大多数的工作都涉及到了Gradle相关的文件操作。

文件对象


在工程目录下,我们可以通过File的构造方法来快速定位一个文件并创建相应的File对象:

// 传入文件的相对路径
File configFile = new File('src/config.xml')

// 传入文件的绝对路径
configFile = new File(configFile.absolutePath)

// 通过相对路径构建一个 java.nio.file.Path 对象并传入
configFile = new File(Paths.get('src', 'config.xml'))

// 读取property变量构建 java.nio.file.Path 对象并传入
configFile = new File(Paths.get(System.getProperty('user.home')).resolve('global-config.xml'))

之所以推荐用new File()的方式来创建对应文件的对象而非 Project.file(java.lang.Object)
方法,主要是因为 file()方法总是把所传入的路径当作以当前工程目录的相对路径来进行解析,而不是当前工作目录。

文件集合


文件集合FileCollection
这个接口描述了针对一组文件的操作和属性。在Gradle中,许多类都继承了这一接口,例如依赖配置对象dependency configurations .
与创建File对象不同,创建FileCollection对象的唯一方式是通过 Project.files(java.lang.Object[])
方法,该方法的入参数目是任意多个,类型也可以是表示相对路径的字符串,File对象,甚至是集合,数组等。

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

对于一个FileCollection对象,我们可以对它进行各种操作:

// 遍历文件集合
collection.each { File file ->
    println file.name
}

// 将FileCollection对象转换为其他类型
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

// 对FileCollection进行加减操作
def union = collection + files('src/file3.txt')
def different = collection - files('src/file3.txt')

files()方法也可以接受closure或者Callable对象作为入参,当FileCollection中文件内容被请求时closure或Callable会被回调,并转换为一个File对象的Set返回。

task list {
    doLast {
        File srcDir

        // 使用closure创建一个FileCollection对象
        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
是用于描述一个树状结构文件集合的对象,它不仅可以表示一个目录下的文件结构,还可以描述一个zip文件中内容。
通过Project对象的fileTree方法,我们可以创建一个目录的FileTree对象。

//创建以src/main为根目录的FileTree
FileTree tree = fileTree(dir: 'src/main')

// 为FileTree添加include和exclude规则
tree.include '**/*.java'
tree.exclude '**/Abstract*'

// 使用路径创建FileTree
tree = fileTree('src').include('**/*.java')

// 使用closure创建FileTree
tree = fileTree('src') {
    include '**/*.java'
}

//使用map创建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
}

//根据规则过滤
FileTree filtered = tree.matching {
    include 'org/gradle/api/**'
}

// 合并两棵FileTree
FileTree sum = tree + fileTree(dir: 'src/test')

// 访问树结构的每个结点
tree.visit {element ->
    println "$element.relativePath => $element.file"
}

上面提到,我们可以把例如zip或tar的压缩文件当做FileTree对象来处理。通过Project的zipTree和tarTree文件,我们可以根据zip文件或tar文件创建出对应的FileTree对象。

FileTree zip = zipTree('someFile.zip')

FileTree tar = tarTree('someFile.tar')

复制文件


通过 Copy
Task,我们可以方便灵活地进行文件的copy操作。在copy的过程中,我们还可以进行文件的重命名,过滤等操作,这都得益于Copy Task继承了CopySpec
接口来让我们指定所要进行的操作。

task anotherCopyTask(type: Copy) {
    //指定所要copy的源文件/源目录
    // copy 目录src/main/webapp下所有文件
    from 'src/main/webapp'
    // Copy 单个文件
    from 'src/staging/index.html'
    // Copy copyTask的输出作为源文件
    from copyTask
    // Copy TaskWithPatterns.outputs
    from copyTaskWithPatterns.outputs
    // Copy Zip 文件中的内容
    from zipTree('src/main/assets.zip')
    // 指定copy操作的输出目录
    into { getDestDir() }
    //通过正则表达式或者closure来指定copy过程中包含或排除的文件
    include '**/*.html'
    include '**/*.jsp'
    exclude { details -> details.file.name.endsWith('.html') &&
                         details.file.text.contains('staging') }
    }

如果copy任务简单,也可以使用Project.copy(org.gradle.api.Action)
方法来进行文件copy。

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

在文件copy过程中,我们可以遍历所要操作的文件,对文件本身进行处理和操作。

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函数接收 closure来修改文件名
    rename { String fileName ->
        fileName.replace('-staging-', '')
    }
    // 使用正则表达式来重命名
    rename '(.+)-staging-(.+)', '$1$2'
    rename(/(.+)-staging-(.+)/, '$1$2')
}
    //在copy过程中也可以用filter对文件内容进行处理
    // 分别替换文件中copyright和version的值为'2009','2.3.1
    // 用properties的键值对进行替换
    expand(copyright: '2009', version: '2.3.1')
    expand(project.properties)
    // filter可以接受FilterReader实例类对文件内容进行操作
    filter(FixCrLfFilter)
    filter(ReplaceTokens, tokens: [copyright: '2009', version: '2.3.1'])
    // 使用 closure 逐行过滤处理文件内容
    filter { String line ->
        "[$line]"
    }
    filter { String line ->
        line.startsWith('-') ? null : line
    }
    filteringCharset = 'UTF-8'

文件下载


利用插件de.undercouch.download,我们可以完成文件下载的相关任务,具体引入和使用方式参见:

de.undercouch.download

执行脚本命令


通过Exec task,我们让gradle脚本来执行命令行脚本或命令。

task stopTomcat(type:Exec) {
  // 工作目录
  workingDir '../tomcat/bin'

  / /执行 ./stop.sh 脚本
  commandLine './stop.sh'

  // 存储命令行打印的结果
  standardOutput = new ByteArrayOutputStream()

  // 通过stopTomcat.output() 即可获得输出
  ext.output = {
    return standardOutput.toString()
  }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,724评论 6 342
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,387评论 25 707
  • 韶光易逝,死亡不远。 以前觉得死亡离我很远很远,毕竟我才二十当头,正处在如花似玉的年纪。回想这二十年我是多么幸运,...
    小柠檬到底萌不萌阅读 529评论 0 0
  • 匆匆又匆匆 万家灯火何时尽 雪入凉光就此觉 夜幕似星阳 笑语对天天叹短 何时风雪似万阳 雪做雨的伴 乘风漂流 你做...
    许枭阅读 104评论 0 1