All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.davfx.ninio.csv.CsvRead Maven / Gradle / Ivy

There is a newer version: 3.0.50
Show newest version
package com.davfx.ninio.csv;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import com.davfx.ninio.csv.dependencies.Dependencies;
import com.davfx.ninio.util.ConfigUtils;
import com.typesafe.config.Config;

public final class CsvRead {
	
	private static final Config CONFIG = ConfigUtils.load(new Dependencies()).getConfig(CsvRead.class.getPackage().getName());
	private static final Charset DEFAULT_CHARSET = Charset.forName(CONFIG.getString("charset"));
	private static final char DEFAULT_DELIMITER = ConfigUtils.getChar(CONFIG, "delimiter");
	private static final char DEFAULT_QUOTE = ConfigUtils.getChar(CONFIG, "quote");
	private static final boolean DEFAULT_IGNORE_EMPTY_LINES = CONFIG.getBoolean("ignoreEmptyLines");

	private Charset charset = DEFAULT_CHARSET;
	private char delimiter = DEFAULT_DELIMITER;
	private char quote = DEFAULT_QUOTE;
	private boolean ignoreEmptyLines = DEFAULT_IGNORE_EMPTY_LINES;
	
	public CsvRead() {
	}
	
	public CsvRead withDelimiter(char delimiter) {
		this.delimiter = delimiter;
		return this;
	}
	public CsvRead withQuote(char quote) {
		this.quote = quote;
		return this;
	}
	public CsvRead withCharset(Charset charset) {
		this.charset = charset;
		return this;
	}
	public CsvRead ignoringEmptyLines(boolean ignoreEmptyLines) {
		this.ignoreEmptyLines = ignoreEmptyLines;
		return this;
	}

	public MayAutoCloseCsvReader from(final InputStream in) {
		final CsvReader csvReader = new CsvReaderImpl(charset, delimiter, quote, ignoreEmptyLines, in);
		return new MayAutoCloseCsvReader() {
			@Override
			public String skip() throws IOException {
				return csvReader.skip();
			}
			@Override
			public Iterable next() throws IOException {
				return csvReader.next();
			}
			
			@Override
			public AutoCloseableCsvReader autoClose() {
				return new AutoCloseableCsvReader() {
					@Override
					public String skip() throws IOException {
						return csvReader.skip();
					}
					@Override
					public Iterable next() throws IOException {
						return csvReader.next();
					}
					
					@Override
					public void close() throws IOException {
						in.close();
					}
				};
			}
		};
	}

	public AutoCloseableCsvReader from(File file) throws IOException {
		return from(new FileInputStream(file)).autoClose();
	}

	public MayAutoCloseCsvKeyedReader parse(final MayAutoCloseCsvReader wrappee) throws IOException {
		final CsvKeyedReader csvReader = new CsvKeyedReaderImpl(wrappee);
		return new MayAutoCloseCsvKeyedReader() {
			@Override
			public Iterable keys() {
				return csvReader.keys();
			}
			@Override
			public Line next() throws IOException {
				return csvReader.next();
			}
			
			@Override
			public AutoCloseableCsvKeyedReader autoClose() {
				final AutoCloseableCsvReader autoCloseableWrappee = wrappee.autoClose();
				return new AutoCloseableCsvKeyedReader() {
					@Override
					public Iterable keys() {
						return csvReader.keys();
					}
					@Override
					public Line next() throws IOException {
						return csvReader.next();
					}
					
					@Override
					public void close() throws IOException {
						autoCloseableWrappee.close();
					}
				};
			}
		};
	}

	public AutoCloseableCsvKeyedReader parse(final AutoCloseableCsvReader wrappee) throws IOException {
		final CsvKeyedReader csvReader = new CsvKeyedReaderImpl(wrappee);
		return new AutoCloseableCsvKeyedReader() {
			@Override
			public Iterable keys() {
				return csvReader.keys();
			}
			@Override
			public Line next() throws IOException {
				return csvReader.next();
			}
			
			@Override
			public void close() throws IOException {
				wrappee.close();
			}
		};
	}

	public MayAutoCloseCsvKeyedReader parse(InputStream in) throws IOException {
		return parse(from(in));
	}

	public AutoCloseableCsvKeyedReader parse(File file) throws IOException {
		return parse(from(file));
	}
	
	private static final class CsvReaderImpl implements CsvReader {
		private final char delimiter;
		private final char quote;
		private final boolean ignoreEmptyLines;

		private final BufferedReader reader;

		public CsvReaderImpl(Charset charset, char delimiter, char quote, boolean ignoreEmptyLines, InputStream in) {
			this.delimiter = delimiter;
			this.quote = quote;
			this.ignoreEmptyLines = ignoreEmptyLines;
			reader = new BufferedReader(new InputStreamReader(in, charset));
		}
		
		@Override
		public String skip() throws IOException {
			while (true) {
				String line = reader.readLine();
				if (line == null) {
					return null;
				}
				
				line = line.trim();
				if (ignoreEmptyLines && line.isEmpty()) {
					continue;
				}

				return line;
			}
		}
		
		@Override
		public Iterable next() throws IOException {
			while (true) {
				String line = reader.readLine();
				if (line == null) {
					return null;
				}
				
				line = line.trim();
				if (ignoreEmptyLines && line.isEmpty()) {
					continue;
				}

				List components = new LinkedList();
				
				int i = 0;
				while (i < line.length()) {
					if (line.charAt(i) == quote) {
						StringBuilder c = new StringBuilder();
						int n = i + 1;
						while (true) {
							int j = line.indexOf(quote, n);
							if (j < 0) {
								String component = line.substring(n);
								c.append(component).append('\n');
								line = reader.readLine();
								n = 0;
								continue;
							}
							if ((j < (line.length() - 1)) && (line.charAt(j + 1) == quote)) {
								String component = line.substring(n, j);
								c.append(component).append(quote);
								n = j + 2;
								continue;
							} else {
								String component = line.substring(n, j);
								c.append(component);
								components.add(c.toString());
								// Next char is ';'
								i = j + 2;
								break;
							}
						}
					} else {
						int j = line.indexOf(delimiter, i);
						if (j < 0) {
							String component = line.substring(i);
							components.add(component);
							i = line.length();
						} else {
							String component = line.substring(i, j);
							components.add(component);
							i = j + 1;
							if (i == line.length()) {
								components.add("");
							}
						}
					}
				}
				return components;
			}
		}
	}
	
	private static final class CsvKeyedReaderImpl implements CsvKeyedReader {
		private final CsvReader csvReader;
		private final List keys = new ArrayList();
		private int currentNumber = 0;
		
		public CsvKeyedReaderImpl(CsvReader csvReader) throws IOException {
			this.csvReader = csvReader;
			
			Iterable n = csvReader.next();
			if (n == null) {
				throw new IOException("Missing keys header");
			}
			for (String key : n) {
				keys.add(key);
			}
		}
		
		@Override
		public Iterable keys() {
			return keys;
		}
		
		private static final class InnerLine implements Line {
			private final int number;
			private final Map values = new LinkedHashMap();
			private InnerLine(List keys, int number, Iterable line) {
				this.number = number;
				int index = 0;
				for (String value : line) {
					if (index == keys.size()) {
						break;
					}
					String key = keys.get(index);
					values.put(key, value);
					index++;
				}
			}
			@Override
			public String get(String key) {
				return values.get(key);
			}
			@Override
			public int number() {
				return number;
			}
			@Override
			public String toString() {
				return "#" + (number + 1) + ":" + values;
			}
		}

		@Override
		public Line next() throws IOException {
			Iterable line = csvReader.next();
			if (line == null) {
				return null;
			}
			int n = currentNumber;
			currentNumber++;
			return new InnerLine(keys, n, line);
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy