Chapter 14. Working With Files

This chapter is a work in progress.

Most builds work with files. Gradle adds some concepts and APIs to help you do this.

14.1. Locating files

You can locate a file relative to the project directory using the Project.file() method.

Example 14.1. Locating files

build.gradle

// Using a relative path
File configFile = file('src/config.xml')

// Using an absolute path
configFile = file(configFile.absolutePath)

// Using a File object with a relative path
configFile = file(new File('src/config.xml'))

You can pass any object to the file() method, though usually you would pass it a String or File. The supplied object's toString() value is treated as a file path. If this path is an absolute path, it is used to construct a File instance. Otherwise, a File instance is constructed by prepending the project directory path to the supplied path.

Using this method is a useful way to convert some user provided value into an absolute File. It is preferable to using new File(somePath), as file() always evaluates the supplied path relative to the project directory, which is fixed, rather than the current working directory, which may not always be the same.

14.2. File collections

A file collection is simply a set of files. It is represented by the FileCollection interface. Many objects in Gradle implement this interface. For example, dependency configurations implement FileCollection.

One way to obtain a FileCollection instance is to use the Project.files() method. You can pass this method any number of objects, which are then converted into a set of File objects. The files() method accepts File and String arguments. These are evaluated relative to the project directory, as described in Section 14.1, “Locating files”. You can also pass collections, maps and arrays to the files() method. These are flattened and the contents converted to File instances.

Example 14.2. Creating a file collection

build.gradle

FileCollection collection = files('src/file1.txt', file('src/file2.txt'), ['src/file3.txt', 'src/file4.txt'])

A file collection is iterable, and can be converted to a number of other types using the as operator. You can also add 2 file collections together using the + operator. Here are some examples.

Example 14.3. Using a file collection

build.gradle

// Iterate over the files in the collection
collection.each {File file ->
    file.name
}

// Convert the collection to various types
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

// Add collections together
def collection2 = collection + files('src/file3.txt')

You can also pass the files() method a closure or a Callable instance. This is called when the contents of the collection are queried, and its return value is converted to a set of File instances. The return value can be an object of any of the types supported by the files() method. This is a simple way to 'implement' the FileCollection interface.

Example 14.4. Implementing a file collection

build.gradle

task list << {
    File srcDir

    // Create a file collection using a closure
    collection = files { srcDir.listFiles() }

    // Create a file collection using a Callable
    Callable callable = { srcDir.listFiles() } as Callable
    collection = files(callable)

    srcDir = file('src')
    println "Contents of $srcDir.name"
    collection.each { println relativePath(it) }

    srcDir = file('src2')
    println "Contents of $srcDir.name"
    collection.each { println relativePath(it) }
}

Output of gradle -q list

> gradle -q list
Contents of src
src/dir1
src/file1.txt
Contents of src2
src2/dir1
src2/dir2

The files() method also accepts FileCollection instances.

14.3. File trees

A file tree is a hierarchy of files, such as a directory tree. It is represented by the FileTree interface. The FileTree interface extends FileCollection, so you can treat a file tree exactly the same way as you would a file collection. Several objects in Gradle implement the FileTree interface, such as source sets.

One way to obtain a FileTree instance is to use the Project.fileTree() method. This creates a FileTree defined with a base directory, and optionally some Ant-style include and exclude patterns.

Example 14.5. Creating a file tree

build.gradle

// Create a file tree with a base directory
def tree = fileTree(dir: 'src/main')

// Add include and exclude patterns to the tree
tree.include '**/*.java'
tree.exclude '**/Abstract*'

// Create a tree using path
tree = fileTree('src').include('**/*.java')

// Create a tree using closure
tree = fileTree {
    from 'src'
    include '**/*.java'
}

// Create a tree using a map
tree = fileTree(dir: 'src', includes: ['**/*.java'])

You use a file tree in the same way you use a file collection. You can also visit the contents of the tree, and select a subtree using Ant-style patterns:

Example 14.6. Using a file tree

build.gradle

// Iterate over the contents of a tree
tree.each {File file ->
    println file
}

// Filter a tree
def filtered = tree.matching {
    include 'org/gradle/api/**'
}

// Add trees together
def sum = tree + fileTree(dir: 'src/test')

// Visit the nodes of the tree
tree.visit {node ->
    println "$node.relativePath => $node.file"
}

14.4. Specifying a set of files

Many objects in Gradle have properties which accept a logical set of files. For example, the Compile task has a source property, which defines the source files to compile. You can set the value of this property using any of the types supported by the files() method, which we have seen above. This means you can set the property using, for example, a File, String, collection, FileCollection or even a closure. Here are some examples:

Example 14.7. Specifying a set of files

build.gradle

compile {
    source = file('src/main/java')
}

compile {
    source = 'src/main/java'
}

compile {
    source = ['src/main/java', '../shared/java']
}

compile {
    source = fileTree(dir: 'src/main/java').matching { include 'org/gradle/api/**' }
}

compile {
    source = {
        fileTree(dir: 'src/main/java') + fileTree(dir: '../shared/java')
    }
}

Usually, there is a method with the same name as the property, which appends to the set of files. Again, this method accepts any of the types supported by the files() method.

Example 14.8. Specifying a set of files

build.gradle

compile {
    source 'src/main/java', 'src/main/groovy'
    source file('../shared/java')
    source { file('src/test/').listFiles() }
}

14.5. Copying files

You can use the Copy task to copy files. The copy task allows you to filter the contents of the files as they are copied, and to map the files names.

Example 14.9. Copying files using the copy task

build.gradle

task copyTask(type: Copy) {
    from 'src/main/webapp'
    into 'build/explodedWar'
    include '**/*.html'
    include '**/*.jsp'
    include 'assets/**'
}

You can also use the Project.copy() method.

Example 14.10. Copying files using the copy() method

build.gradle

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