FileDocCategorySizeDatePackage
InputStreamReader.javaAPI DocAndroid 1.5 API22804Wed May 06 22:41:04 BST 2009java.io

InputStreamReader

public class InputStreamReader extends Reader
A class for turning a byte stream into a character stream. Data read from the source input stream is converted into characters by either a default or a provided character converter. The default encoding is taken from the "file.encoding" system property. {@code InputStreamReader} contains a buffer of bytes read from the source stream and converts these into characters as needed. The buffer size is 8K.
see
OutputStreamWriter
since
Android 1.0

Fields Summary
private InputStream
in
private static final int
BUFFER_SIZE
private boolean
endOfInput
CharsetDecoder
decoder
ByteBuffer
bytes
Constructors Summary
public InputStreamReader(InputStream in)
Constructs a new {@code InputStreamReader} on the {@link InputStream} {@code in}. This constructor sets the character converter to the encoding specified in the "file.encoding" property and falls back to ISO 8859_1 (ISO-Latin-1) if the property doesn't exist.

param
in the input stream from which to read characters.
since
Android 1.0


                                                                       
       
        super(in);
        this.in = in;
        String encoding = AccessController
                .doPrivileged(new PriviAction<String>(
                        "file.encoding", "ISO8859_1")); //$NON-NLS-1$//$NON-NLS-2$
        decoder = Charset.forName(encoding).newDecoder().onMalformedInput(
                CodingErrorAction.REPLACE).onUnmappableCharacter(
                CodingErrorAction.REPLACE);
    
public InputStreamReader(InputStream in, String enc)
Constructs a new InputStreamReader on the InputStream {@code in}. The character converter that is used to decode bytes into characters is identified by name by {@code enc}. If the encoding cannot be found, an UnsupportedEncodingException error is thrown.

param
in the InputStream from which to read characters.
param
enc identifies the character converter to use.
throws
NullPointerException if {@code enc} is {@code null}.
throws
UnsupportedEncodingException if the encoding specified by {@code enc} cannot be found.
since
Android 1.0

        super(in);
        if (enc == null) {
            throw new NullPointerException();
        }
        this.in = in;
        try {
            decoder = Charset.forName(enc).newDecoder().onMalformedInput(
                    CodingErrorAction.REPLACE).onUnmappableCharacter(
                    CodingErrorAction.REPLACE);
        } catch (IllegalArgumentException e) {
            throw new UnsupportedEncodingException();
        }
    
public InputStreamReader(InputStream in, CharsetDecoder dec)
Constructs a new InputStreamReader on the InputStream {@code in} and CharsetDecoder {@code dec}.

param
in the source InputStream from which to read characters.
param
dec the CharsetDecoder used by the character conversion.
since
Android 1.0

        super(in);
        dec.averageCharsPerByte();
        this.in = in;
        decoder = dec;
    
public InputStreamReader(InputStream in, Charset charset)
Constructs a new InputStreamReader on the InputStream {@code in} and Charset {@code charset}.

param
in the source InputStream from which to read characters.
param
charset the Charset that defines the character converter
since
Android 1.0

        super(in);
        this.in = in;
        decoder = charset.newDecoder().onMalformedInput(
                CodingErrorAction.REPLACE).onUnmappableCharacter(
                CodingErrorAction.REPLACE);
    
Methods Summary
public voidclose()
Closes this reader. This implementation closes the source InputStream and releases all local storage.

throws
IOException if an error occurs attempting to close this reader.
since
Android 1.0

        synchronized (lock) {
            // BEGIN android-added
            if (decoder != null) {
                decoder.reset();
            }
            // END android-added
            decoder = null;
            if (in != null) {
                in.close();
                in = null;
            }
        }
    
public java.lang.StringgetEncoding()
Returns the name of the encoding used to convert bytes into characters. The value {@code null} is returned if this reader has been closed.

return
the name of the character converter or {@code null} if this reader is closed.
since
Android 1.0

        if (!isOpen()) {
            return null;
        }
        return HistoricalNamesUtil.getHistoricalName(decoder.charset().name());
    
private booleanisOpen()

        return in != null;
    
public intread()
Reads a single character from this reader and returns it as an integer with the two higher-order bytes set to 0. Returns -1 if the end of the reader has been reached. The byte value is either obtained from converting bytes in this reader's buffer or by first filling the buffer from the source InputStream and then reading from the buffer.

return
the character read or -1 if the end of the reader has been reached.
throws
IOException if this reader is closed or some other I/O error occurs.
since
Android 1.0

        synchronized (lock) {
            if (!isOpen()) {
                // K0070=InputStreamReader is closed.
                throw new IOException(Msg.getString("K0070")); //$NON-NLS-1$
            }

            char buf[] = new char[1];
            return read(buf, 0, 1) != -1 ? buf[0] : -1;
        }
    
public intread(char[] buf, int offset, int length)
Reads at most {@code length} characters from this reader and stores them at position {@code offset} in the character array {@code buf}. Returns the number of characters actually read or -1 if the end of the reader has been reached. The bytes are either obtained from converting bytes in this reader's buffer or by first filling the buffer from the source InputStream and then reading from the buffer.

param
buf the array to store the characters read.
param
offset the initial position in {@code buf} to store the characters read from this reader.
param
length the maximum number of characters to read.
return
the number of characters read or -1 if the end of the reader has been reached.
throws
IndexOutOfBoundsException if {@code offset < 0} or {@code length < 0}, or if {@code offset + length} is greater than the length of {@code buf}.
throws
IOException if this reader is closed or some other I/O error occurs.
since
Android 1.0

        synchronized (lock) {
            if (!isOpen()) {
                // K0070=InputStreamReader is closed.
                throw new IOException(Msg.getString("K0070")); //$NON-NLS-1$
            }
            // BEGIN android-changed
            // Exception priorities (in case of multiple errors) differ from
            // RI, but are spec-compliant.
            // made implicit null check explicit, used (offset | length) < 0
            // instead of (offset < 0) || (length < 0) to safe one operation
            if (buf == null) {
                throw new NullPointerException(Msg.getString("K0047")); //$NON-NLS-1$
            }
            if ((offset | length) < 0 || offset > buf.length - length) {
                throw new IndexOutOfBoundsException(Msg.getString("K002f")); //$NON-NLS-1$
            }
            // END android-changed
            if (length == 0) {
                return 0;
            }
            
            // allocate enough space for bytes if the default length is
            // inadequate
            int availableLen = in.available();     
            if (Math.min(availableLen, length) > bytes.capacity()) {
                bytes = ByteBuffer.allocate(availableLen);
            }
            
            CharBuffer out = CharBuffer.wrap(buf, offset, length);
            CoderResult result = CoderResult.UNDERFLOW;
            byte[] a = bytes.array();
            boolean has_been_read = false;

            if (!bytes.hasRemaining() || bytes.limit() == bytes.capacity()) {
                // Nothing is available in the buffer...
                if (!bytes.hasRemaining()) {
                    bytes.clear();
                }
                int readed = in.read(a, bytes.arrayOffset(), bytes.remaining());
                if (readed == -1) {
                    endOfInput = true;
                    return -1;
                }
                bytes.limit(readed);
                has_been_read = true;
            }

            while (out.hasRemaining()) {
                if (bytes.hasRemaining()) {
                    result = decoder.decode(bytes, out, false);
                    if (!bytes.hasRemaining() && endOfInput) {
                        decoder.decode(bytes, out, true);
                        decoder.flush(out);
                        decoder.reset();
                        break;
                    }
                    if (!out.hasRemaining()
                            || bytes.position() == bytes.limit()) {
                        bytes.compact();
                    }
                }
                if (in.available() > 0
                        && (!has_been_read && out.hasRemaining())
                        || out.position() == 0) {
                    bytes.compact();
                    int to_read = bytes.remaining();
                    int off = bytes.arrayOffset() + bytes.position();

                    to_read = in.read(a, off, to_read);
                    if (to_read == -1) {
                        if (bytes.hasRemaining()) {
                            bytes.flip();
                        }
                        endOfInput = true;
                        break;
                    }
                    has_been_read = true;
                    if (to_read > 0) {
                        bytes.limit(bytes.position() + to_read);
                        bytes.position(0);
                    }
                } else {
                    break;
                }
            }

            if (result == CoderResult.UNDERFLOW && endOfInput) {
                result = decoder.decode(bytes, out, true);
                // FIXME: should flush at first, but seems ICU has a bug that it
                // will throw IAE if some malform/unmappable bytes found during
                // decoding
                // result = decoder.flush(chars);
                decoder.reset();
            }
            if (result.isMalformed()) {
                throw new MalformedInputException(result.length());
            } else if (result.isUnmappable()) {
                throw new UnmappableCharacterException(result.length());
            }
            if (result == CoderResult.OVERFLOW && bytes.position() != 0) {
                bytes.flip();
            }

            return out.position() - offset == 0 ? -1 : out.position() - offset;
        }
    
public booleanready()
Indicates whether this reader is ready to be read without blocking. If the result is {@code true}, the next {@code read()} will not block. If the result is {@code false} then this reader may or may not block when {@code read()} is called. This implementation returns {@code true} if there are bytes available in the buffer or the source stream has bytes available.

return
{@code true} if the receiver will not block when {@code read()} is called, {@code false} if unknown or blocking will occur.
throws
IOException if this reader is closed or some other I/O error occurs.
since
Android 1.0

        synchronized (lock) {
            if (in == null) {
                // K0070=InputStreamReader is closed.
                throw new IOException(Msg.getString("K0070")); //$NON-NLS-1$
            }
            try {
                return bytes.limit() != bytes.capacity() || in.available() > 0;
            } catch (IOException e) {
                return false;
            }
        }