ZetCode

Groovy CSV Processing

last modified October 15, 2026

CSV (comma-separated values) is a simple text format for tables, and many exports from spreadsheets and databases use it. Splitting each line on commas works for clean data, but a quoted field that contains a comma breaks that approach. In this tutorial, we read CSV files with the core splitEachLine method, see where it fails, and then parse and write CSV with CsvSlurper and CsvBuilder from the groovy-csv module.

Reading a file line by line is covered in the Groovy file I/O tutorial.

Reading Lines with splitEachLine

splitEachLine is a method on File and on String. For each line, it splits the text at the given separator and passes the resulting list of fields to a closure. It needs no extra library.

people.csv
name,age,city
Alice,30,Paris
Bob,25,"New York, NY"
Carol,41,Berlin

The first line is a header that names the three columns. Each following line is one record, and its fields are separated by commas. Bob's city is written as "New York, NY": the quotes tell a CSV parser that the comma belongs to the value. The examples below read this file in different ways, so the quoted field shows where each approach works and where it fails.

SumAges.groovy
def total = 0
def count = 0
new File('people.csv').splitEachLine(',') { fields ->
    if (fields[0] == 'name') return
    total += fields[1].trim().toInteger()
    count++
}
println "people: $count, average age: ${total / count}"

The header row is recognized by its first field and skipped with return, which ends the closure for that line. The age column is trimmed, converted to an integer, and added to the total. The division total / count gives 32 here, because 96 divided by 3 is exact.

$ groovy SumAges.groovy
people: 3, average age: 32

Where splitEachLine Fails

The file above contains "New York, NY", a city name with a comma inside quotes. splitEachLine does not understand quoting, so it splits at that comma as well.

Split.groovy
new File('people.csv').splitEachLine(',') { fields ->
    println fields
}

The Bob row now has four pieces instead of three: the city is split into "New York and NY", and the leading space and quote are kept. Any code that reads a fixed column index would take the wrong value. Hand-written regular expressions for quoted fields exist, but they are hard to get right, so a real CSV parser is the better choice when the data can contain quotes or line breaks inside fields.

$ groovy Split.groovy
[name, age, city]
[Alice, 30, Paris]
[Bob, 25, "New York,  NY"]
[Carol, 41, Berlin]

Parsing CSV with CsvSlurper

CsvSlurper, from the groovy.csv package, parses CSV text using a full CSV parser. It handles quoted fields, and by default it uses the first line as the header. Each data row becomes a map from header name to value. The class is provided by the groovy-csv module, which is added to the classpath as org.apache.groovy:groovy-csv. This article's examples were run with version 6.0.0.

CsvSlurperDemo.groovy
import groovy.csv.CsvSlurper

def rows = new CsvSlurper().parse(new File('people.csv'))
rows.each { row ->
    println "${row.name} | ${row.age} | ${row.city}"
}
println "count: ${rows.size()}"

parse reads the file and returns a list of rows. Each row is accessed by its column name, so row.city returns the value from the city column. The quoted field is now a single value.

def rows = new CsvSlurper().parse(new File('people.csv'))

CsvSlurper also has parseText for strings, and parse accepts a Reader, an InputStream, a Path, or a File.

$ groovy CsvSlurperDemo.groovy
Alice | 30 | Paris
Bob | 25 | New York, NY
Carol | 41 | Berlin
count: 3

Custom Separators

Many European spreadsheet exports use a semicolon as the separator, because the comma is used as the decimal mark. The setSeparator method changes the separator before parsing.

Semicolon.groovy
import groovy.csv.CsvSlurper

def parsed = new CsvSlurper().setSeparator(';' as char)
        .parseText('id;total\n1;9.50\n2;3.00')
println parsed
println parsed.collect { it.total as BigDecimal }.sum()

The values are read as strings, so it.total as BigDecimal converts each one before summing. Using BigDecimal keeps the decimal amounts exact, which matters for money.

$ groovy Semicolon.groovy
[[id:1, total:9.50], [id:2, total:3.00]]
12.50

Writing CSV with CsvBuilder

CsvBuilder.toCsv takes a collection of maps and produces CSV text. The header is taken from the keys of the first map, and values that contain the separator are quoted automatically.

WriteCsv.groovy
import groovy.csv.CsvBuilder

def rows = [[name: 'Dan', age: 52, city: 'Rome']]
new File('out.csv').text = CsvBuilder.toCsv(rows)
println new File('out.csv').text

The file is written with the text property, and the same text is then read back and printed.

The output ends with an empty line because the generated text already ends with a newline and println adds another one.

$ groovy WriteCsv.groovy
name,age,city
Dan,52,Rome

About toCsvReader

toCsvReader is not a method of the Groovy releases used for this article: the Groovy 5.0.1 distribution does not provide it, and calling it on a File, a Reader, or a String fails with MissingMethodException. The jars of Groovy 3.0.22, 4.0.24, and 6.0.0 were also checked and do not contain it. To read CSV, use splitEachLine for simple data, or CsvSlurper when fields can contain separators or quotes. Examples that use toCsvReader should be updated to one of these.

Best Practices

Source

Groovy documentation

This tutorial showed how to read CSV with splitEachLine, why it fails on quoted fields, how to parse CSV with CsvSlurper using headers and custom separators, and how to write CSV with CsvBuilder.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than eight years of experience in teaching programming.

List all Groovy tutorials.