Files and I/O
Prerequisites: Exceptions and error handling
The GDK adds convenient methods to java.io.File and java.nio.file.Path,
so most file tasks take one line.
def file = new File('notes.txt')
file.text = 'first line\n' // write (replaces the file)
file << 'second line\n' // append
file.append('third line\n')
println file.text
println file.readLines().size()
println file.exists()
println file.length()
first line
second line
third line
3
true
34
file.text reads the whole file as a string; assigning to it writes the
file. Both use UTF-8 by default on current JDKs — pass a charset
explicitly (file.getText('UTF-8')) when a file might come from
elsewhere.
Reading line by line
def csv = new File('scores.csv')
csv.text = '''name,score
ada,91
linus,78
grace,88
'''
csv.eachLine { line, number ->
if (number == 1) return // skip the header
def (name, score) = line.split(',')
println "${name.padRight(6)} ${score.toInteger() >= 80 ? 'pass+' : 'pass'}"
}
def best = csv.readLines().drop(1)
.collect { it.split(',') }
.max { it[1].toInteger() }
println "best: ${best[0]}"
ada pass+
linus pass
grace pass+
best: ada
eachLine streams the file one line at a time — use it (or
withReader) for large files instead of reading everything with
text.
Writing with a writer
def report = new File('report.txt')
report.withWriter('UTF-8') { w ->
w.writeLine 'Report'
w.writeLine '======'
(1..3).each { w.writeLine "item $it" }
}
println report.text
report.withPrintWriter { pw -> pw.printf('%s has %d chars%n', 'Groovy', 6) }
println report.text
Report
======
item 1
item 2
item 3
Groovy has 6 chars
withWriter opens the file, passes a writer to your closure, and
closes it afterwards — even if the closure throws.
Directories
def dir = new File('project')
new File(dir, 'src').mkdirs()
new File(dir, 'src/App.groovy').text = 'println "app"'
new File(dir, 'README.md').text = '# Project'
new File(dir, 'build.gradle').text = "plugins { id 'groovy' }"
def files = []
dir.eachFileRecurse { f ->
if (f.isFile()) files << dir.toPath().relativize(f.toPath()).toString().replace('\\', '/')
}
println files.sort()
println dir.listFiles().findAll { it.name.endsWith('.md') }*.name
println dir.deleteDir()
println dir.exists()
[README.md, build.gradle, src/App.groovy]
[README.md]
true
false
eachFileRecurse walks a directory tree; deleteDir removes a
directory and everything inside it. The iteration order of files
depends on the file system, so sort results when order matters.
Paths (java.nio)
import java.nio.file.*
def path = Path.of('data.txt')
path.text = 'alpha\nbeta\n'
println path.readLines()
println Files.size(path)
println path.fileName
Files.delete(path)
println Files.exists(path)
[alpha, beta]
11
data.txt
false
Modern Java code prefers Path to File; Groovy gives both the same
conveniences.