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

你可能感兴趣的:(Gradle 文件操作)