diff --git a/pom.xml b/pom.xml index 9ce484af77b07d390741e2a61b088ea497643a74..ce4dc4876f751cdd8faf12155897ce829e59af36 100644 --- a/pom.xml +++ b/pom.xml @@ -3,6 +3,10 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + <groupId>edu.unl.cse.csv_io</groupId> <artifactId>csv_io</artifactId> @@ -41,6 +45,11 @@ <version>4.12</version> <scope>test</scope> </dependency> + <dependency> + <groupId>com.opencsv</groupId> + <artifactId>opencsv</artifactId> + <version>5.0</version> + </dependency> </dependencies> </project> diff --git a/src/main/java/edu/unl/cse/csv_io/CSVReaderWriter.java b/src/main/java/edu/unl/cse/csv_io/CSVReaderWriter.java index 90d7e477b3c9eb2631acf018f586cf77be5ecbfe..29d1ec0a47175298a9eb7ee8ee805b843e2b27fb 100644 --- a/src/main/java/edu/unl/cse/csv_io/CSVReaderWriter.java +++ b/src/main/java/edu/unl/cse/csv_io/CSVReaderWriter.java @@ -2,28 +2,68 @@ * CSV Reader/Writer, copyright (c) 2019 Christopher A. Bohn, bohn@unl.edu. */ - package edu.unl.cse.csv_io; +import com.opencsv.CSVReaderHeaderAware; +import com.opencsv.CSVReaderHeaderAwareBuilder; +import com.opencsv.exceptions.CsvValidationException; + import java.io.*; import java.net.URL; import java.util.*; public class CSVReaderWriter { - // this does not (yet) handle data elements that include commas and/or are surrounded by quotation marks - private static final String DELIMTER = ","; - private static final char BYTE_ORDER_MARK = '\ufeff'; + @SuppressWarnings("WeakerAccess") + public static Set<Map<String, String>> readCSVasSet(String filename) { + Set<Map<String, String>> csvSet = null; + try (InputStreamReader inputStreamReader = new InputStreamReader(Objects.requireNonNull( + CSVReaderWriter.class.getClassLoader().getResourceAsStream("csv/" + filename)))) { + csvSet = (Set<Map<String, String>>) parseCSV(inputStreamReader, new HashSet<>()); + } catch (NullPointerException nullPointerException) { + System.err.println("Check spelling of file " + filename + "."); + System.exit(1); + } catch (IOException ioException) { + System.err.println("Error loading " + filename + ". " + ioException); + System.exit(1); + } catch (CsvValidationException csvValidationException) { + System.err.println("Could not validate a line in " + filename + ". " + csvValidationException); + System.exit(1); + } + return csvSet; + } + private static Collection<Map<String, String>> parseCSV(InputStreamReader inputStreamReader, + Collection<Map<String, String>> destination) + throws IOException, CsvValidationException { + Map<String, String> line; + try { + CSVReaderHeaderAware csvReader = new CSVReaderHeaderAwareBuilder(inputStreamReader).build(); + while ((line = csvReader.readMap()) != null) { + destination.add(line); + } + } catch (NullPointerException ignored) { + // CSVReaderHeaderAwareBuilder.build() throws NullPointerException if inputStreamReader is empty + } + return destination; + } + + /* LEGACY METHODS */ + @SuppressWarnings("WeakerAccess") + public static Set<Map<String, String>> readCSV(String filename) { + return readCSVasSet(filename); + } +/* public static Set<Map<String, String>> readCSV(String filename) { Set<Map<String, String>> csvSet = null; ClassLoader classLoader = CSVReaderWriter.class.getClassLoader(); - try(InputStream inputStream = classLoader.getResourceAsStream("csv/"+filename)) { + try (InputStream inputStream = classLoader.getResourceAsStream("csv/" + filename)) { csvSet = parseCSV(inputStream); } catch (IOException ioException) { System.err.println("Error loading " + filename + ". " + ioException); } return csvSet; } +*/ public static boolean writeCSV(String filename, Set<Map<String, String>> data) { boolean wroteFile = true; @@ -31,7 +71,7 @@ public class CSVReaderWriter { URL resource = classLoader.getResource("csv/" + filename); if (resource != null) { File file = new File(resource.getPath()); - try(OutputStream outputStream = new FileOutputStream(file)) { + try (OutputStream outputStream = new FileOutputStream(file)) { placeCSVonStream(data, outputStream); } catch (FileNotFoundException fileNotFoundException) { System.err.println("Could not open " + filename + "; probably due to a bad pathname. " + fileNotFoundException); @@ -47,6 +87,16 @@ public class CSVReaderWriter { return wroteFile; } + + static Set<Map<String, String>> parseCSV(InputStream inputStream) throws IOException { + try { + return (Set<Map<String, String>>) parseCSV(new InputStreamReader(inputStream), new HashSet<>()); + } catch (CsvValidationException csvValidationException) { + csvValidationException.printStackTrace(); + return null; + } + } +/* static Set<Map<String, String>> parseCSV(InputStream inputStream) throws IOException { Set<Map<String, String>> csvSet = new HashSet<>(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); @@ -57,14 +107,15 @@ public class CSVReaderWriter { String[] elements = line.split(DELIMTER); if (header) { if (elements[0].charAt(0) == BYTE_ORDER_MARK) { - elements[0] = elements[0].substring(1); // remove text-encoding character sometimes added by Excel + elements[0] = elements[0].substring(1); // remove text-encoding character sometimes added by + // Excel } fieldNames.addAll(Arrays.asList(elements)); header = false; } else { Map<String, String> row = new HashMap<>(); int column = 0; - for (String element: elements) { + for (String element : elements) { row.put(fieldNames.get(column++), element); } csvSet.add(row); @@ -72,35 +123,66 @@ public class CSVReaderWriter { } return csvSet; } +*/ static void placeCSVonStream(Set<Map<String, String>> data, OutputStream outputStream) { PrintStream writer = new PrintStream(outputStream); Set<String> fieldNames = null; int number_of_fields = 0; - for (Map<String, String> row: data) { + for (Map<String, String> row : data) { int field_number = 0; if (fieldNames == null) { fieldNames = row.keySet(); number_of_fields = fieldNames.size(); - for (String field: fieldNames) { + for (String field : fieldNames) { writer.print(field); - writer.print(++field_number<number_of_fields ? "," : "\n"); + writer.print(++field_number < number_of_fields ? "," : "\n"); } } field_number = 0; - for (String field: fieldNames) { + for (String field : fieldNames) { String value = row.get(field); writer.print(value != null ? value : ""); - writer.print(++field_number<number_of_fields ? "," : "\n"); + writer.print(++field_number < number_of_fields ? "," : "\n"); } } } + /* + public static void main(String[] args) { + Set<Map<String, String>> demo = readCSV("demo.csv"); + boolean success = writeCSV("out.csv", demo); + System.out.println(success ? "Wrote file!" : "Didn't write file"); + } + */ /* public static void main(String[] args) { - Set<Map<String, String>> demo = readCSV("demo.csv"); - boolean success = writeCSV("out.csv", demo); - System.out.println(success ? "Wrote file!" : "Didn't write file"); + Set<Map<String,String>> students = readCSV("students.csv"); + for (Map<String,String> student: students) { + System.out.println(student.get("Name")); + } + } +*//* + public static void main(String[] args) { + Set<Map<String, String>> courses = readCSV("courses.csv"); + for (Map<String, String> course : courses) { + String foo = course.get("URL"); + if (foo == null) { + foo = "Null object"; + } else if (foo.equals("")) foo = "Empty String"; + System.out.println(course.get("CourseID") + " " + course.get("Section") + " " + foo + " " + course.get( + "Prerequisite1")); + } + }*/ + public static void main(String[] args) { + Set<Map<String, String>> courses = readCSV("empty.csv"); + for (Map<String, String> course : courses) { + String foo = course.get("URL"); + if (foo == null) { + foo = "Null object"; + } else if (foo.equals("")) foo = "Empty String"; + System.out.println(course.get("CourseID") + " " + course.get("Section") + " " + foo + " " + course.get( + "Prerequisite1")); + } } -*/ } diff --git a/src/main/resources/csv/empty.csv b/src/main/resources/csv/empty.csv new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/test/java/edu/unl/cse/csv_io/CSVReaderWriterTest.java b/src/test/java/edu/unl/cse/csv_io/CSVReaderWriterTest.java index 5b8641b2475ff8ae3dbef6303d849dc75158bb17..12e27b653371350ea56e1a19523203106f8f567e 100644 --- a/src/test/java/edu/unl/cse/csv_io/CSVReaderWriterTest.java +++ b/src/test/java/edu/unl/cse/csv_io/CSVReaderWriterTest.java @@ -10,6 +10,7 @@ import java.util.*; import static org.junit.Assert.*; import static org.hamcrest.CoreMatchers.*; +@SuppressWarnings("unchecked") // pee-yew! public class CSVReaderWriterTest { private static InputStream inputStream; private static OutputStream outputStream; @@ -58,11 +59,12 @@ public class CSVReaderWriterTest { Set<String> expectedKeys = new HashSet<>(Arrays.asList(headers)); // Oracle -- Rows Map<String, String> expectedRow = new HashMap<>(); - for (int i=0; i<headers.length; i++) { + for (int i = 0; i < headers.length; i++) { expectedRow.put(headers[i], row[i]); } // Compare - Map<String,String> aRow = (Map<String,String>)result.toArray()[0]; + assertNotNull(result); + Map<String, String> aRow = (Map<String, String>) result.toArray()[0]; assertEquals(expectedKeys, aRow.keySet()); assertTrue(result.contains(expectedRow)); } @@ -86,21 +88,22 @@ public class CSVReaderWriterTest { // Oracle -- Rows Map<String, String>[] expectedRows = new Map[2]; for (int i = 0; i < expectedRows.length; i++) { - expectedRows[i] = new HashMap<String, String>(); + expectedRows[i] = new HashMap<>(); for (int j = 0; j < headers.length; j++) { expectedRows[i].put(headers[j], rows[i][j]); } } // Compare + assertNotNull(result); Map<String, String> aRow = (Map<String, String>) result.toArray()[0]; assertEquals(expectedKeys, aRow.keySet()); - for (Map<String, String> expectedRow: expectedRows) { + for (Map<String, String> expectedRow : expectedRows) { assertTrue(result.contains(expectedRow)); } } @Test - public void testParsingCSVwithOnlyHeaderRow() { + public void testParsingCSVWithOnlyHeaderRow() { // Input String[] headers = {"header1", "header2"}; String[][] data = {headers}; @@ -146,7 +149,7 @@ public class CSVReaderWriterTest { String[] headers = {"header1", "header2"}; String[][] rows = {{"datum1", "datum2"}, {"datum3", "datum4"}}; Map<String, String>[] inputRows = new Map[2]; - for (int i=0; i<inputRows.length; i++) { + for (int i = 0; i < inputRows.length; i++) { inputRows[i] = new HashMap<>(2); inputRows[i].put(headers[0], rows[i][0]); inputRows[i].put(headers[1], rows[i][1]);