/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package java.io;
/**
* Reader is an Abstract class for reading Character Streams. Subclasses of
* Reader must implement the methods read(char[], int, int)
and
* close()
.
*
* @see Writer
*/
public abstract class Reader {
/**
* The object used to synchronize access to the reader.
*/
protected Object lock;
/**
* Constructs a new character stream Reader using this
as the
* Object to synchronize critical regions around.
*/
protected Reader() {
super();
lock = this;
}
/**
* Constructs a new character stream Reader using lock
as the
* Object to synchronize critical regions around.
*
* @param lock
* the Object
to synchronize critical regions
* around.
*/
protected Reader(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
/**
* Close this Reader. This must be implemented by any concrete subclasses.
* The implementation should free any resources associated with the Reader.
*
* @throws IOException
* If an error occurs attempting to close this Reader.
*/
public abstract void close() throws IOException;
/**
* Set a Mark position in this Reader. The parameter readLimit
* indicates how many characters can be read before a mark is invalidated.
* Sending reset() will reposition the reader back to the marked position
* provided readLimit
has not been surpassed.
*
* This default implementation simply throws IOException and concrete
* subclasses must provide their own implementations.
*
* @param readLimit
* an int representing how many characters must be read before
* invalidating the mark.
*
* @throws IOException
* If an error occurs attempting mark this Reader.
*/
public void mark(int readLimit) throws IOException {
throw new IOException();
}
/**
* Answers a boolean indicating whether or not this Reader supports mark()
* and reset(). This class a default implementation which answers false.
*
* @return true
if mark() and reset() are supported,
* false
otherwise. This implementation returns
* false
.
*/
public boolean markSupported() {
return false;
}
/**
* Reads a single character from this reader and returns the result as an
* int. The 2 higher-order characters are set to 0. If the end of reader was
* encountered then return -1.
*
* @return the character read or -1 if end of reader.
*
* @throws IOException
* If the Reader is already closed or some other IO error
* occurs.
*/
public int read() throws IOException {
synchronized (lock) {
char charArray[] = new char[1];
if (read(charArray, 0, 1) != -1) {
return charArray[0];
}
return -1;
}
}
/**
* Reads characters from this Reader and stores them in the character array
* buf
starting at offset 0. Returns the number of characters
* actually read or -1 if the end of reader was encountered.
*
* @param buf
* character array to store the read characters
* @return how many characters were successfully read in or else -1 if the
* end of the reader was detected.
*
* @throws IOException
* If the Reader is already closed or some other IO error
* occurs.
*/
public int read(char buf[]) throws IOException {
return read(buf, 0, buf.length);
}
/**
* Reads at most count
characters from this Reader and stores
* them at offset
in the character array buf
.
* Returns the number of characters actually read or -1 if the end of reader
* was encountered.
*
* @param buf
* character array to store the read characters
* @param offset
* offset in buf to store the read characters
* @param count
* how many characters should be read in
* @return how many characters were successfully read in or else -1 if the
* end of the reader was detected.
*
* @throws IOException
* If the Reader is already closed or some other IO error
* occurs.
*/
public abstract int read(char buf[], int offset, int count)
throws IOException;
/**
* Answers a boolean
indicating whether or not this Reader is
* ready to be read without blocking. If the result is true
,
* the next read()
will not block. If the result is
* false
this Reader may or may not block when
* read()
is sent.
*
* @return true
if the receiver will not block when
* read()
is called, false
if unknown
* or blocking will occur.
*
* @throws IOException
* If the Reader is already closed or some other IO error
* occurs.
*/
public boolean ready() throws IOException {
return false;
}
/**
* Reset this Readers position to the last mark()
location.
* Invocations of read()/skip()
will occur from this new
* location. If this Reader was not marked, the implementation of
* reset()
is implementation specific. See the comment for
* the specific Reader subclass for implementation details. The default
* action is to throw IOException
.
*
* @throws IOException
* If a problem occured or the receiver does not support
* mark()/reset()
.
*/
public void reset() throws IOException {
throw new IOException();
}
/**
* Skips count
number of characters in this Reader.
* Subsequent read()
's will not return these characters
* unless reset()
is used. This method may perform multiple
* reads to read count
characters.
*
* @param count
* how many characters should be passed over
* @return how many characters were successfully passed over
*
* @throws IOException
* If the Reader is closed when the call is made or if an IO
* error occurs during the operation.
*/
public long skip(long count) throws IOException {
if (count < 0) {
throw new IllegalArgumentException();
}
synchronized (lock) {
long skipped = 0;
int toRead = count < 512 ? (int) count : 512;
char charsSkipped[] = new char[toRead];
while (skipped < count) {
int read = read(charsSkipped, 0, toRead);
if (read == -1) {
return skipped;
}
skipped += read;
if (read < toRead) {
return skipped;
}
if (count - skipped < toRead) {
toRead = (int) (count - skipped);
}
}
return skipped;
}
}
}