09.03.04 java.io.Reader und java.io.Writer

Sie kennen aus den letzten Kapiteln bereits die Klassen java.io.InputStream und java.io.OutputStream. Dieses Kapitel befasst sich mit den beiden verbleibenden Basis-Streams java.io.Reader und java.io.Writer. Da sich diese beiden abstrakten Klassen nur sehr wenig von den bereits bekannten unterscheiden, soll an dieser Stelle ein gemeinsames Kapitel für den Reader und den Writer genügen.

Der Hauptunterschied liegt darin, dass Reader und Writer im Gegensatz zu InputStream und OutputStream nur mit Zeichen (char) umgehen können. Dies ist immer dann nützlich, wenn Sie mit gewöhnlichem Text arbeiten. Aus diesem Grund arbeiten die Methoden der Reader und Writer auch in den meisten Fällen (ausgenommen sind read() und write(int i)) ausschließlich mit Zeichen oder Zeichenketten.

Konkret wurde beim Reader im Vergleich zum InputStream aus der Methode read(byte[] b) die Methode read(char[] cbuf), und aus read(byte[] b, int off, int len) die Methode read(char[] cbuf, int off, int len). Zusätzlich wurden die Methoden read(CharBuffer target), welche versucht, die zu lesenden Zeichen in einen CharBuffer zu speichern und ready(), welche true zurückliefert, falls der Reader alle Daten verarbeitet hat, so dass mit dem Lesen begonnen werden kann, hinzugefügt. Dafür entfällt die Methode available der InputStream-Klasse. Anbei der Quellcode der Reader-Klasse zum besseren Verständnis.

package java.io;

public abstract class Reader implements Readable, Closeable {

  protected Object lock;

  protected Reader() {
    this.lock = this;
  }

  protected Reader(Object lock) {
    if (lock == null) {
      throw new NullPointerException();
    }
    this.lock = lock;
  }

  public int read(java.nio.CharBuffer target) throws IOException {
    int len = target.remaining();
    char[] cbuf = new char[len];
    int n = read(cbuf, 0, len);
    if (n > 0)
      target.put(cbuf, 0, n);
    return n;
  }

  public int read() throws IOException {
    char cb[] = new char[1];
    if (read(cb, 0, 1) == -1)
      return -1;
    else
      return cb[0];
  }

  public int read(char cbuf[]) throws IOException {
    return read(cbuf, 0, cbuf.length);
  }

  abstract public int read(char cbuf[], int off, int len) throws IOException;

  private static final int maxSkipBufferSize = 8192;

  private char skipBuffer[] = null;

  public long skip(long n) throws IOException {
    if (n < 0L) 
      throw new IllegalArgumentException("skip value is negative");
    int nn = (int) Math.min(n, maxSkipBufferSize);
    synchronized (lock) {
      if ((skipBuffer == null) || (skipBuffer.length < nn))
        skipBuffer = new char&#91;nn&#93;;
      long r = n;
      while (r > 0) {
        int nc = read(skipBuffer, 0, (int)Math.min(r, nn));
        if (nc == -1)
          break;
        r -= nc;
      }
      return n - r;
    }
  }

  public boolean ready() throws IOException {
    return false;
  }

  public boolean markSupported() {
    return false;
  }

  public void mark(int readAheadLimit) throws IOException {
    throw new IOException("mark() not supported");
  }

  public void reset() throws IOException {
    throw new IOException("reset() not supported");
  }

  abstract public void close() throws IOException;
}

Im Gegensatz zum InputStream muss bei Readern die close-Methode überschrieben werden. Die read()-Methode hingegen nicht, dafür aber read(char cbuf[], int off, int len).

Beim Writer ist die Situation ähnlich. Aus write(byte[] b) und write(byte[] b, int off, int len) wird write(char[] cbuf) und write(char[] cbuf, int off, int len). close() und flush() bleiben erhalten, sind aber abstrakt. Zusätzlich gibt es noch die Möglichkeit, write mit einem String anstelle eines char-Arrays aufzurufen. Dies ist auch möglich, wenn nicht der komplette String geschrieben werden soll. Hierfür wird write(String str, int off, int len) verwendet. Alternativ können die write-Aufrufe auch durch append-Methoden mit einer CharSequence bzw. einem char als Übergabeparameter ersetzt werden. Diese rufen aber prinzipiell nur die entsprechenden write-Methoden auf.

package java.io;

public abstract class Writer implements Appendable, Closeable, Flushable {

private char[] writeBuffer;

private final int writeBufferSize = 1024;

protected Object lock;

protected Writer() {
this.lock = this;
}

protected Writer(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}

public void write(int c) throws IOException {
synchronized (lock) {
if (writeBuffer == null){
writeBuffer = new char[writeBufferSize];
}
writeBuffer[0] = (char) c;
write(writeBuffer, 0, 1);
}
}

public void write(char cbuf[]) throws IOException {
write(cbuf, 0, cbuf.length);
}

abstract public void write(char cbuf[], int off, int len) throws IOException;

public void write(String str) throws IOException {
write(str, 0, str.length());
}

public void write(String str, int off, int len) throws IOException {
synchronized (lock) {
char cbuf[];
if (len <= writeBufferSize) { if (writeBuffer == null) { writeBuffer = new char[writeBufferSize]; } cbuf = writeBuffer; } else { // Don't permanently allocate very large buffers. cbuf = new char[len]; } str.getChars(off, (off + len), cbuf, 0); write(cbuf, 0, len); } } public Writer append(CharSequence csq) throws IOException { if (csq == null) write("null"); else write(csq.toString()); return this; } public Writer append(CharSequence csq, int start, int end) throws IOException { CharSequence cs = (csq == null ? "null" : csq); write(cs.subSequence(start, end).toString()); return this; } public Writer append(char c) throws IOException { write(c); return this; } abstract public void flush() throws IOException; abstract public void close() throws IOException; }[/sourcecode] Auch bei einem Writer muss write(char cbuf[], int off, int len) anstelle von write(char c) überschrieben werden.

2 Replies to “09.03.04 java.io.Reader und java.io.Writer”

  1. Cyrill Brunner

    Etwas verwirrt mich an dem Quellcode zu der Klasse Reader:

    public int read(java.nio.CharBuffer target) throws IOException {
    int len = target.remaining();
    char[] cbuf = new char[len];
    int n = read(cbuf, 0, len);
    if (n > 0)
    target.put(cbuf, 0, n);
    return n;
    }

    Mit target.put wird ja der übergebene CharBuffer manipuliert. Soweit ich weiss, benutzt eine Methode doch eigentlich nur Kopien der Übergabeparamater, und nicht die Übergabeparamerter selbst, oder hab ich was völlig falsch verstanden?

    Gruss
    Cyrill

Schreibe einen Kommentar

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.