Step 1 of 5 · Reading · ~2 min
Learn
Strings, Regex, I/O
Groovy makes file I/O concise. Most of the API below is Groovy JDK sugar layered on java.io.File.
Reading a file
def file = new File("data.txt")
file.text // entire content as String
file.bytes // entire content as byte[]
file.readLines() // List<String>
file.eachLine { line, num ->
println "$num: $line"
}
eachLine hands the closure the line and a 1-based line number.
Writing
new File("out.txt").text = "hello" + '\n' // REPLACES the file
new File("log.txt") << "appended" // appends
Assigning .text truncates first; << on a File appends. Reaching for the wrong one silently destroys a log.
Stream-style for big files
new File("big.csv").withReader { reader ->
def line
while ((line = reader.readLine()) != null) {
process(line)
}
}
withReader closes the reader when the block exits, however it exits — that is the whole point of the with* family, and it is why you rarely write a try/finally around a file in Groovy. withWriter, withInputStream and withOutputStream behave the same way.
Walking a directory
new File("src").eachFile { f -> println f.name } // children
new File("src").eachFileRecurse { f -> // and below
if (f.name.endsWith(".groovy")) println f.absolutePath
}
stdin and stdout
This is the part the grader actually exercises, because a submission has no filesystem to speak of — it has a pipe on stdin.
System.in.eachLine { line, num -> println "$num: $line" }
def all = System.in.text // everything at once
def one = System.in.newReader().readLine() // a single line
printf("%-10s %d" + '\n', "hi", 42) // C-style
System.in.eachLine takes the same one- or two-argument closure as the File version, so the numbering comes for free.
Asking about a file
def f = new File("data.txt")
f.exists(); f.size(); f.canRead(); f.isDirectory(); f.lastModified()
Running a process
def proc = "git status".execute()
proc.waitForOrKill(5000)
println proc.text // stdout
println proc.exitValue() // 0 or non-zero
// piping needs two PROCESSES, not two strings:
def out = ("ls -la".execute() | "grep groovy".execute()).text
String.execute() is what turns the command into a Process; | is defined on Process, not on String.
Your exercise
Number the lines arriving on stdin. The mistake the grader catches is starting the count at 0 — eachLine's counter is 1-based, so trust it rather than keeping your own.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…