Skip to content

Instantly share code, notes, and snippets.

@johncarl81
Last active November 9, 2018 21:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johncarl81/36aa049df75e21fa86b0240eae982e57 to your computer and use it in GitHub Desktop.
Save johncarl81/36aa049df75e21fa86b0240eae982e57 to your computer and use it in GitHub Desktop.
Simple CSV writer and reader
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