de.unkrig.commons.io.LineUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of de-unkrig-commons Show documentation
Show all versions of de-unkrig-commons Show documentation
A versatile Java(TM) library that implements many useful container and utility classes.
/*
* de.unkrig.commons - A general-purpose Java class library
*
* Copyright (c) 2012, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package de.unkrig.commons.io;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import de.unkrig.commons.lang.protocol.Consumer;
import de.unkrig.commons.lang.protocol.ConsumerWhichThrows;
import de.unkrig.commons.lang.protocol.Producer;
import de.unkrig.commons.lang.protocol.ProducerWhichThrows;
import de.unkrig.commons.nullanalysis.Nullable;
/**
* Various utility methods for processing "lines", i.e. sequences of strings (which typically don't contain line
* breaks).
*/
public final
class LineUtil {
private static final Charset CHARSET_ISO_8859_1 = Charset.forName("ISO-8859-1");
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
private
LineUtil() {}
/**
* Produces lines from a ISO 8859-1-encoded {@link InputStream}.
*/
public static ProducerWhichThrows
lineProducerISO8859_1(InputStream in) { // SUPPRESS CHECKSTYLE MethodName|AbbreviationAsWord
return LineUtil.lineProducer(new InputStreamReader(in, LineUtil.CHARSET_ISO_8859_1));
}
/**
* Produces lines from a {@link Reader}.
*/
public static ProducerWhichThrows
lineProducer(Reader r) {
final BufferedReader br = r instanceof BufferedReader ? (BufferedReader) r : new BufferedReader(r);
return new ProducerWhichThrows() {
@Override public String
produce() throws IOException {
return br.readLine();
}
};
}
/**
* Produces lines from a string by splitting that at line breaks.
*/
public static Producer
lineProducer(final String text) {
return new Producer() {
final int len = text.length();
int offset;
@Override @Nullable public String
produce() {
if (this.offset == this.len) return null;
for (int o = this.offset;;) {
char c = text.charAt(o);
if (c == '\r') {
final String result = text.substring(this.offset, o);
o++;
if (o < this.len && text.charAt(o) == '\n') o++;
this.offset = o;
return result;
}
if (c == '\n') {
String result = text.substring(this.offset, o);
this.offset = o + 1;
return result;
}
o++;
if (o == this.len) {
// Final line w/o trailing line separator.
String result = text.substring(this.offset);
this.offset = o;
return result;
}
}
}
};
}
/**
* Produces lines from a CharSequence by splitting that at line breaks.
*/
public static Producer
lineProducer(final CharSequence text) {
return new Producer() {
final int len = text.length();
int offset;
@Override @Nullable public CharSequence
produce() {
if (this.offset == this.len) return null;
for (int o = this.offset;;) {
char c = text.charAt(o);
if (c == '\r') {
final CharSequence result = text.subSequence(this.offset, o);
o++;
if (o < this.len && text.charAt(o) == '\n') o++;
this.offset = o;
return result;
}
if (c == '\n') {
CharSequence result = text.subSequence(this.offset, o);
this.offset = o + 1;
return result;
}
o++;
if (o == this.len) {
// Final line w/o trailing line separator.
CharSequence result = text.subSequence(this.offset, o);
this.offset = o;
return result;
}
}
}
};
}
/**
* Similar to {@link java.io.BufferedReader#readLine()}, except that
*
* - The produced strings include the line separator
* -
* Not only CR, LF and CRLF are recognized as line terminators, but also some other special characters, as
* described here
*
*
*
* @param r The source of characters
* @return Produces one string for each parsed line and {@code null} at end-of-input
*/
public static ProducerWhichThrows
readLineWithSeparator(final Reader r) {
return new ProducerWhichThrows() {
private int lookahead = -2;
@Override @Nullable public String
produce() throws IOException {
int c;
if (this.lookahead == -2) {
c = r.read();
} else {
c = this.lookahead;
this.lookahead = -2;
}
if (c == -1) return null;
StringBuilder sb = new StringBuilder();
for (;;) {
sb.append((char) c);
if (
c == '\n' // Newline (line feed) character
|| c == '\u0085' // Next-line character
|| c == '\u2028' // Line-separator character
|| c == '\u2029' // Paragraph-separator character
) return sb.toString();
if (c == '\r') {
c = r.read();
if (c == '\n') {
// A carriage-return character followed immediately by a newline character
return sb.append('\n').toString();
}
// A standalone carriage-return character
this.lookahead = c;
return sb.toString();
}
c = r.read();
if (c == -1) return sb.toString();
}
}
};
}
/**
* Writes the consumed strings as lines to the ISO 8859-1-encoded {@link OutputStream}.
*/
public static ConsumerWhichThrows
lineConsumerISO8859_1(OutputStream out) { // SUPPRESS CHECKSTYLE MethodName|AbbreviationAsWord
return LineUtil.lineConsumer(new OutputStreamWriter(out, LineUtil.CHARSET_ISO_8859_1));
}
/**
* Writes the consumed strings as lines to the given {@link Writer}.
*/
public static ConsumerWhichThrows
lineConsumer(final Writer w) {
return new ConsumerWhichThrows() {
@Override public void
consume(String line) throws IOException {
w.write(line + LineUtil.LINE_SEPARATOR);
w.flush();
}
};
}
/**
* Prints the consumed strings as lines to the given {@link PrintWriter}.
*/
public static Consumer
lineConsumer(final PrintWriter pw) {
return new Consumer() { @Override public void consume(T line) { pw.println(line); } };
}
/**
* Prints the consumed strings as lines to the given {@link PrintStream}.
*/
public static Consumer
lineConsumer(final PrintStream ps) {
return new Consumer() {
@Override public void consume(String line) { ps.println(line); }
};
}
/**
* Reads lines from the given reader until end-of-input.
*/
public static List
readAllLines(Reader r, boolean closeReader) throws IOException {
try {
BufferedReader br = r instanceof BufferedReader ? (BufferedReader) r : new BufferedReader(r);
final List result = new ArrayList();
for (;;) {
String line = br.readLine();
if (line == null) break;
result.add(line);
}
if (closeReader) r.close();
return result;
} finally {
if (closeReader) {
try { r.close(); } catch (Exception e) {}
}
}
}
}