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

ch.inftec.ju.util.io.NewLineReader Maven / Gradle / Ivy

package ch.inftec.ju.util.io;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

import org.apache.commons.lang3.StringUtils;

/**
 * Reader that is aware of new line characters, i.e. that will try to auto detect what kind of NewLine
 * the file uses (\r\n, \r or \n).
 * 

* Initially, the newLine property will be set to null. If left to null, the Reader will set it to the * value of the NewLine string as soon as it encounters the first new line. After that, all following * lines are treated accordingly. *

* If set manually, the reader will treat the new lines accordingly to the value set. E.g. if the * newLine string ist set manually to '\n' and the Reader encounters a '\r\n', the '\r' will be * part of the string returned. * @author Martin * */ public class NewLineReader extends Reader { public static String LF = "\n"; public static String CRLF = "\r\n"; /** * Input new line String. */ private String inputNewLine = null; /** * Output new line String. */ private String outputNewLine = null; /** * Buffer for characters that have been read from the underlying reader. * This will already contain the converted output NewLines (if different * from the input NewLines). */ private Queue queue = new LinkedList<>(); /** * Reader the NewLineReader works with. */ private Reader reader; /** * Creates a new NewLineReader by an innput String. * @param s String * @return NewLineReader */ public static NewLineReader createByString(String s) { return new NewLineReader(new StringReader(s)); } /** * Creates a new NewLineReader, using the same input and output NewLine * Strings as used in the character stream. * @param reader Reader to read character stream from */ public NewLineReader(Reader reader) { this(reader, null, null); } /** * Creates a new NewLineReader using the specified input and output NewLine * Strings. * @param reader Reader to read character stream from * @param inputNewLine Input NewLine String. If null, it is auto detected from the first * occurrence of a newLine String in the stream. If not null, it must be either 1 or * two characters. * @param outputNewLine Output NewLine String. If null, the same NewLine String as * the input NewLine String is used */ public NewLineReader(Reader reader, String inputNewLine, String outputNewLine) { this.reader = reader; if (StringUtils.length(inputNewLine) > 2 || StringUtils.length(outputNewLine) > 2) { throw new IllegalArgumentException("Input and Output NewLine characters can not be longer than 2 characters."); } if (inputNewLine != null && inputNewLine.length() == 0) { throw new IllegalArgumentException("Input NewLine may not be empty String"); } this.inputNewLine = inputNewLine; this.outputNewLine = outputNewLine; } /** * Gets the Input NewLine character used or detected by this Reader. If none * has been specified and the Reader hasn't encountered any, null is returned. * @return Input NewLine String or null if not known */ public String getInputNewLine() { return this.inputNewLine; } /** * Gets the Output NewLine character used by this Reader. If none has been * specified and the Reader hasn't encountered any, null is returned. * @return Output NewLine String or null if not known */ public String getOutputNewLine() { return this.outputNewLine; } @Override public void close() throws IOException { this.reader.close(); } @Override public int read(char[] cbuf, int off, int len) throws IOException { this.doRead(len); if (this.queue.size() == 0) return -1; int i = off; int lastIndex = off + len - 1; while (i <= lastIndex && this.queue.size() > 0) { cbuf[i] = this.queue.poll(); i++; } return i-off; } /** * Makes sure the queue holds the the specified amount of characters. If the stream * doesn't provide enough characters, as much as possible are read. * @param len Characters to be read into the queue. If the stream ends * before, we'll read as many characters as possible. * @throws IOException If the next character cannot be read */ private void doRead(int len) throws IOException { while (this.queue.size() < len) { if (!this.readFirstChar()) return; } } /** * Reads a character from the underlying reader. If the character could be part * of a two character new line sequence, another character will be read. The * character(s) will be added to the reader's queue. * @return False if the end of the reader was reached, true otherwise * @throws IOException */ private boolean readFirstChar() throws IOException { int nextChInt = this.reader.read(); if (nextChInt == -1) return false; char nextCh = (char)nextChInt; if (this.inputNewLine != null && this.inputNewLine.charAt(0) == nextCh) { if (this.inputNewLine.length() == 1) { this.addNewLine(); } else { return this.readSecondChar(nextCh); } } else if (this.inputNewLine == null && nextCh == '\n') { this.inputNewLine = "\n"; this.addNewLine(); } else if (this.inputNewLine == null && nextCh == '\r') { return this.readSecondChar(nextCh); } else { this.queue.add(nextCh); } return true; } /** * Reads the second character of a possible NewLine combination from the reader. * The characters will be added to the reader's queue * @param firstCh First character * @return False if the end of the reader was reached, true otherwise * @throws IOException If the character canot be read */ private boolean readSecondChar(char firstCh) throws IOException { // Try to read second character. int nextChInt = this.reader.read(); if (nextChInt == -1) { if (this.inputNewLine == null && firstCh == '\r' || firstCh == '\n') { // First char IS NewLine this.inputNewLine = Character.toString(firstCh); this.addNewLine(); } else { // No NewLine found this.queue.add(firstCh); } return false; } // Next character was not null char nextCh = (char)nextChInt; if (this.inputNewLine != null) { if (this.inputNewLine.charAt(1) == nextCh) { this.addNewLine(); } else { this.queue.add(firstCh); this.queue.add(nextCh); } } else { // First character must have been '\r' if (nextCh == '\n') { this.inputNewLine = "\r\n"; this.addNewLine(); } else { this.inputNewLine = "\r"; this.addNewLine(); this.queue.add(nextCh); } } return true; } /** * Adds a new (output) NewLine to the queue. */ private void addNewLine() { if (this.outputNewLine == null) this.outputNewLine = this.inputNewLine; for (int i = 0; i < this.outputNewLine.length(); i++) this.queue.add(this.outputNewLine.charAt(i)); } @Override public void reset() throws IOException { this.reader.reset(); this.queue.clear(); } /** * Creates a new LineIterator instance on this reader. * @return LineIterator */ public LineIterator iterateLines() { return new LineIterator(this); } /** * Gets a list of all lines this reader yields. * @return List of lines */ public List getLines() { List lines = new ArrayList<>(); for (LineIterator i = this.iterateLines(); i.hasNext(); ) { lines.add(i.next()); } return lines; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy