====== 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()}") }