One of the key features of any build tool is I/O operations and how easily you can perform the I/O operations such as reading files, writing files, and directory-related operations. Developers with Ant or Maven backgrounds know how painful and complex it was to handle the files and directory operations in old build tools; sometimes you had to write custom tasks and plugins to perform these kinds of operations due to XML limitations in Ant and Maven. Since Gradle uses Groovy, it will make your life much easier while dealing with files and directory-related operations.
Gradle provides simple ways to read the file. You just need to use the File API (application programing interface) and it provides everything to deal with the file. The following is the code snippet from FileExample/build.gradle
:
task showFile << { File file1 = file("readme.txt") println file1 // will print name of the file file1.eachLine { println it // will print contents line by line } }
To read the file, we have used file(<file Name>)
. This is the default Gradle way to reference files because Gradle adds some path behavior ($PROJECT_PATH/<filename>)
due to absolute and relative referencing of files. Here, the first println
statement will print the name of the file which is readme.txt
. To read a file, Groovy provides the eachLine
method to the File
API, which reads all the lines of the file one by one.
To access the directory, you can use the following file API:
def dir1 = new File("src") println "Checking directory "+dir1.isFile() // will return false for directory println "Checking directory "+dir1.isDirectory() // will return true for directory
To write to the files, you can use either the append
method to add contents to the end of the file or overwrite the file using the setText
or write
methods:
task fileWrite << { File file1 = file ("readme.txt") // will append data at the end file1.append(" Adding new line. ") // will overwrite contents file1.setText("Overwriting existing contents") // will overwrite contents file1.write("Using write method") }
You can create a new file by just writing some text to it:
task createFile << { File file1 = new File("newFile.txt") file1.write("Using write method") }
By writing some data to the file, Groovy will automatically create the file if it does not exist.
To write content to file you can also use the leftshift operator (<<
), it will append data at the end of the file:
file1 << "New content"
If you want to create an empty file, you can create a new file using the createNewFile()
method.
task createNewFile << { File file1 = new File("createNewFileMethod.txt") file1.createNewFile() }
A new directory can be created using the mkdir
command. Gradle also allows you to create nested directories in a single command using mkdirs
:
task createDir << { def dir1 = new File("folder1") dir1.mkdir() def dir2 = new File("folder2") dir2.createTempDir() def dir3 = new File("folder3/subfolder31") dir3.mkdirs() // to create sub directories in one command }
In the preceding example, we are creating two directories, one using mkdir()
and the other using createTempDir()
. The difference is when we create a directory using createTempDir()
, that directory gets automatically deleted once your build script execution is completed.
We will see examples of some of the frequently used methods while dealing with files, which will help you in build automation:
task fileOperations << { File file1 = new File("readme.txt") println "File size is "+file1.size() println "Checking existence "+file1.exists() println "Reading contents "+file1.getText() println "Checking directory "+file1.isDirectory() println "File length "+file1.length() println "Hidden file "+file1.isHidden() // File paths println "File path is "+file1.path println "File absolute path is "+file1.absolutePath println "File canonical path is "+file1.canonicalPath // Rename file file1.renameTo("writeme.txt") // File Permissions file1.setReadOnly() println "Checking read permission "+ file1.canRead()+" write permission "+file1.canWrite() file1.setWritable(true) println "Checking read permission "+ file1.canRead()+" write permission "+file1.canWrite() }
Most of the preceding methods are self-explanatory. Try to execute the preceding task and observe the output. If you try to execute the fileOperations
task twice, you will get the exception readme.txt (No such file or directory)
since you have renamed the file to writeme.txt
.
Certain file methods allow users to pass a regular expression as an argument. Regular expressions can be used to filter out only the required data, rather than fetch all the data. The following is an example of the eachFileMatch()
method, which will list only the Groovy files in a directory:
task filterFiles << { def dir1 = new File("dir1") dir1.eachFileMatch(~/.*.groovy/) { println it } dir1.eachFileRecurse { dir -> if(dir.isDirectory()) { dir.eachFileMatch(~/.*.groovy/) { println it } } } }
The output is as follows:
$ gradle filterFiles :filterFiles dir1groovySample.groovy dir1subdir1groovySample1.groovy dir1subdir2groovySample2.groovy dir1subdir2subDir3groovySample3.groovy BUILD SUCCESSFUL
Gradle provides the
delete()
and deleteDir()
APIs to delete files and directories respectively:
task deleteFile << { def dir2 = new File("dir2") def file1 = new File("abc.txt") file1.createNewFile() dir2.mkdir() println "File path is "+file1.absolutePath println "Dir path is "+dir2.absolutePath file1.delete() dir2.deleteDir() println "Checking file(abc.txt) existence: "+file1.exists()+" and Directory(dir2) existence: "+dir2.exists() }
The output is as follows:
$ gradle deleteFile :deleteFile File path is Chapter6/FileExample/abc.txt Dir path is Chapter6/FileExample/dir2 Checking file(abc.txt) existence: false and Directory(dir2) existence: false BUILD SUCCESSFUL
The preceding task will create a directory dir2
and a file abc.txt
. Then it will print the absolute paths and finally delete them. You can verify whether it is deleted properly by calling the exists()
function.
Until now, we have dealt with single file operations. Gradle provides plenty of user-friendly APIs to deal with file collections. One such API is FileTree. A FileTree represents a hierarchy of files or directories. It extends the FileCollection
interface. Several objects in Gradle such as sourceSets
, implement the FileTree
interface. You can initialize FileTree with the fileTree()
method. The following are the different ways you can initialize the fileTree
method:
task fileTreeSample << { FileTree fTree = fileTree('dir1') fTree.each { println it.name } FileTree fTree1 = fileTree('dir1') { include '**/*.groovy' } println "" fTree1.each { println it.name } println "" FileTree fTree2 = fileTree(dir:'dir1',excludes:['**/*.groovy']) fTree2.each { println it.absolutePath } }
Execute the gradle fileTreeSample
command and observe the output. The first iteration will print all the files in dir1
. The second iteration will only include Groovy files (with extension .groovy
). The third iteration will exclude Groovy files (with extension .groovy
) and print other files with absolute path.
You can also use FileTree to read contents from the archive files such as ZIP, JAR, or TAR files:
FileTree jarFile = zipTree('SampleProject-1.0.jar') jarFile.each { println it.name }
The preceding code snippet will list all the files contained in a jar
file.
3.14.246.148