Last active
November 9, 2018 21:59
-
-
Save johncarl81/36aa049df75e21fa86b0240eae982e57 to your computer and use it in GitHub Desktop.
Simple CSV writer and reader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package test; | |
import java.io.*; | |
import java.util.*; | |
/** | |
* @author John Ericksen | |
*/ | |
public class CSVMarshaller { | |
private static final String QUOTE = "\""; | |
private static final String NEWLINE = "\n"; | |
private static final String COMMA = ","; | |
public void write(List<List<String>> values, OutputStream stream) throws IOException { | |
try(Writer writer = new OutputStreamWriter(stream)) { | |
for (List<String> line : values) { | |
boolean first = true; | |
for(String value : line) { | |
if(first) { | |
first = false; | |
} else { | |
writer.write(COMMA); | |
} | |
writer.write(QUOTE); | |
writer.write(escape(value)); | |
writer.write(QUOTE); | |
} | |
writer.write(NEWLINE); | |
} | |
} | |
} | |
private String escape(String value) { | |
return value.replace(QUOTE, QUOTE + QUOTE); | |
} | |
public List<List<String>> read(InputStream stream) throws IOException, MarshallerException { | |
List<List<String>> output = new ArrayList<>(); | |
try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) { | |
for(String line = reader.readLine(); line != null; line = reader.readLine()) { | |
List<String> lineValues = new ArrayList<>(); | |
int previousSingleQuote = 1; | |
int nextSingleQuote = findNextSingeQuote(line, previousSingleQuote); | |
while(nextSingleQuote != -1) { | |
assertCharacter(line, QUOTE, previousSingleQuote-1); | |
assertCharacter(line, QUOTE, nextSingleQuote); | |
String value = line.substring(previousSingleQuote, nextSingleQuote).replaceAll("\"\"", "\""); | |
lineValues.add(value); | |
previousSingleQuote = nextSingleQuote + 3; | |
if(nextSingleQuote + 1 < line.length()) { | |
assertCharacter(line, COMMA, nextSingleQuote + 1); | |
} | |
nextSingleQuote = findNextSingeQuote(line, previousSingleQuote); | |
} | |
output.add(lineValues); | |
} | |
} | |
return output; | |
} | |
private void assertCharacter(String line, String expected, int index) throws MarshallerException { | |
String value = line.substring(index, index + 1); | |
if (!value.equals(expected)) { | |
throw new MarshallerException("Line \"" + line + | |
"\" at index " + index + | |
" expected: " + expected + | |
" but was " + value); | |
} | |
} | |
private static class MarshallerException extends Exception { | |
public MarshallerException(String message) { | |
super(message); | |
} | |
} | |
private int findNextSingeQuote(String line, int previousSingleQuote) { | |
int startingPoint = previousSingleQuote; | |
int nextSingleQuote = line.indexOf("\"", startingPoint); | |
int nextDoubleQuote = line.indexOf("\"\"", startingPoint); | |
while(nextSingleQuote == nextDoubleQuote && nextSingleQuote != -1) { | |
nextSingleQuote = line.indexOf("\"", startingPoint); | |
nextDoubleQuote = line.indexOf("\"\"", startingPoint); | |
startingPoint = nextSingleQuote + 2; | |
} | |
return nextSingleQuote; | |
} | |
public static void main(String[] args) throws Exception { | |
List<List<String>> values = new ArrayList<>(); | |
values.add(Arrays.asList("\"a\"", "b,c,d", "e")); | |
values.add(Arrays.asList("1,2,3", "\"4\",\"5", "6\"78\"", "hey")); | |
values.add(Arrays.asList("another test", "\"\"\"\"\"\"")); | |
CSVMarshaller marshaller = new CSVMarshaller(); | |
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); | |
marshaller.write(values, outputStream); | |
try(OutputStream fileOut = new FileOutputStream("output.csv")) { | |
fileOut.write(outputStream.toByteArray()); | |
} | |
List<List<String>> outputValues = marshaller.read(new ByteArrayInputStream(outputStream.toByteArray())); | |
for(int i = 0; i < values.size(); i++) { | |
for(int j = 0; j < values.get(i).size(); j++) { | |
if(outputValues.size() > i && outputValues.get(i).size() > j) { | |
String original = values.get(i).get(j); | |
String output = outputValues.get(i).get(j); | |
if(!original.equals(output)) { | |
throw new Exception("Not equal at " + i + ", " + j + ", original: " + original + " output: " + output); | |
} | |
} else { | |
throw new Exception("Size not the same."); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment