====== Reading CSV Files ======
- Adding Apache commons csv library as dependencies
- Putting your csv file in the project
- Read the CSV file in your code
===== Adding apache commons text library as dependencies =====
Put the following in your build.gradle dependencies{} section. The current version of commons cvs is 1.6. You might want to use a newer version upon its release.
compile group: 'org.apache.commons', name: 'commons-csv', version: '1.6'
===== Putting your csv file in the project =====
For Grails 3 project, one of the good place to store your file is the ''/grails-app/conf'' directory. You can even create your own directory within it. We are going to use **MTR Lines (except Airport Express & Light Rail) Fares** ''mtr_lines_fares.csv'' as an example, and it can be downloaded at [[https://data.gov.hk/en-data/dataset/mtr-data-routes-fares-barrier-free-facilities|here]].
{{ :reading_csv_files1.png?direct&200 |}}
The data look like the follow. Play attention to the header.
^ SRC_STATION_NAME ^ SRC_STATION_ID ^ DEST_STATION_NAME ^ DEST_STATION_ID ^ OCT_ADT_FARE ^ OCT_STD_FARE ^ SINGLE_ADT_FARE ^ OCT_CON_CHILD_FARE ^ OCT_CON_ELDERLY_FARE ^ OCT_CON_PWD_FARE ^ SINGLE_CON_CHILD_FARE ^ SINGLE_CON_ELDERLY_FARE
| Central | 1 | Central | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
| Central | 1 | Admiralty | 2 | 4.6 | 3 | 5 | 3 | 2 | 2 | 3 | 3
| ... ||
===== Read the CSV file in your code =====
We can read the csv in a Grails controller or service. We are going to do this in a controller.
class PriceController {
def grailsResourceLocator
def index() {
String strings = grailsResourceLocator.findResourceForURI('classpath:/mtr_lines_fares.csv').inputStream.getText(StandardCharsets.UTF_8.name())
Iterable records = CSVFormat.RFC4180.withFirstRecordAsHeader().parse(new StringReader(strings))
StringBuilder sb = new StringBuilder()
for (CSVRecord cvsRecord : records) {
try {
sb.append(cvsRecord.get("SRC_STATION_NAME")).append(", ")
sb.append(cvsRecord.get("SRC_STATION_ID")).append(", ")
sb.append(cvsRecord.get("DEST_STATION_NAME")).append(", ")
sb.append(cvsRecord.get("DEST_STATION_ID")).append(", ")
sb.append(cvsRecord.get("OCT_ADT_FARE")).append(", ")
sb.append(cvsRecord.get("OCT_STD_FARE")).append(", ")
sb.append(cvsRecord.get("SINGLE_ADT_FARE")).append(", ")
sb.append(cvsRecord.get("OCT_CON_CHILD_FARE")).append(", ")
sb.append(cvsRecord.get("OCT_CON_ELDERLY_FARE")).append(", ")
sb.append(cvsRecord.get("OCT_CON_PWD_FARE")).append(", ")
sb.append(cvsRecord.get("SINGLE_CON_CHILD_FARE")).append(", ")
sb.append(cvsRecord.get("SINGLE_CON_ELDERLY_FARE"))
sb.append("
")
} catch (Exception ignored) {
log.error("Unable to convert ${cvsRecord.toString()}")
}
}
render(sb.toString())
}
}
First we load our csv file with grailsResourceLocator.
String strings = grailsResourceLocator.findResourceForURI('classpath:/mtr_lines_fares.csv').inputStream.getText(StandardCharsets.UTF_8.name())
Than parse it with ''withFirstRecordAsHeader''. It will return an iterable CSVRecord, which is basically a map with headers as keys.
Iterable records = CSVFormat.RFC4180.withFirstRecordAsHeader().parse(new StringReader(strings))
With the iterable records, we can use a loop to loop though them to extract the data we want. Here we use the csv header as the key to obtains data in each column.
for (CSVRecord cvsRecord : records) {
try {
sb.append(cvsRecord.get("SRC_STATION_NAME")).append(", ")
.
.
.
} catch (Exception ignored) {
log.error("Unable to convert ${cvsRecord.toString()}")
}
{{ :reading_csv_files2.png?direct&400 |}}
===== CSV without header =====
You can parse the string with
Iterable records = CSVFormat.RFC4180.parse(new StringReader(strings))
And loop though the records with
for (CSVRecord cvsRecord : records) {
try {
sb.append(cvsRecord.get(0).append(", ")
sb.append(cvsRecord.get(1).append(", ")
sb.append(cvsRecord.get(2).append(", ")
.
.
.
} catch (Exception ignored) {
log.error("Unable to convert ${cvsRecord.toString()}")
}