A BufferedReader which returns line terminators
I am working on a parser which must take into account line numbers, and make correlations between them and document’s offsets. For instance, I need to know at which line is the character #145 of a given text file. The problem is that different OSs use different line terminators: \n on Linux, \r\n on Windows, \r on Mac.
I could not modify the original document in any way, so I needed a trustable way to work on them in a platform-independent way. One simple way to count lines in a text file would be using Java’s BufferedReader. Unfortunately this class provides no way of knowing which line terminators are used for every line of text, what prevents using the lenght of the read buffer to determinate the current offset while reading.
That’s why I wrote this simple class.It provides two methods: readLine(), working as the usual BufferedReader’s one, but returning also line terminators (at the end of the line), and a readChars(), useful for knowing the current offset while reading the stream.
I wrote some tests also to test if it works in any case, and so far I didn’t know of unsolved problems. Feel free to use it if you want, and let me know if you find any bug.
import java.io.IOException;
import java.io.Reader;
public class MyBufferedReader {
private Reader delegate;
private StringBuilder readBuffer;
private int nextCh = SOL;
private int readChars;
private static final int SOL = -10; // Start Of Line
public TplBufferedReader(Reader delegate) {
this.delegate = delegate;
readBuffer = new StringBuilder();
}
/**
* Reads all chars of a line, returning also line terminators
*
* @return The line text
*/
public String readLine() throws IOException {
String res = null;
readBuffer.setLength(0);
int ch = (char) -10;
if (nextCh == -1) {
res = null;
} else {
boolean newLine = false;
boolean eof = false;
while (!newLine && !eof) {
if (nextCh != SOL){
readBuffer.append((char)nextCh);
}
nextCh = SOL;
ch = delegate.read();
switch (ch) {
case '\r':
// check for double newline char
nextCh = delegate.read();
if (nextCh == '\n') {
// double line found
readBuffer.append("\r\n");
newLine = true;
nextCh = SOL;
} else {
readBuffer.append("\r");
newLine = true;
}
break;
case '\n':
readBuffer.append("\n");
newLine = true;
break;
case -1:
eof = true;
nextCh = -1;
break;
default:
if (ch != -1) readBuffer.append((char)ch);
}
}
res = readBuffer.toString();
readChars += res.length();
}
return res;
}
public void close() throws IOException{
delegate.close();
}
public int readChars() {
return readChars;
}
}
