In Put Stream Reader
In Put Stream Reader
io;
import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CoderResult; import java.nio.charset.CodingErrorAction; import java.nio.charset.MalformedInputException; import java.nio.charset.UnmappableCharacterException; import java.util.Arrays;
/** 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 */ public class InputStreamReader extends Reader { private 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 * */ public InputStreamReader(InputStream in) { this(in, Charset.defaultCharset()); } the input stream from which to read characters.
/** * 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. *
* @throws UnsupportedEncodingException * */ public InputStreamReader(InputStream in, final String enc) throws UnsupportedEncodingException { 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 (UnsupportedEncodingException) new UnsupportedEncodingException(enc).initCause(e); } bytes.limit(0); if the encoding specified by {@code enc} cannot be found.
/** * 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 * */ public InputStreamReader(InputStream in, CharsetDecoder dec) { super(in); dec.averageCharsPerByte(); this.in = in; decoder = dec; bytes.limit(0); } the CharsetDecoder used by the character conversion.
/** * 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 * */ public InputStreamReader(InputStream in, Charset charset) { super(in); this.in = in; decoder = charset.newDecoder().onMalformedInput( CodingErrorAction.REPLACE).onUnmappableCharacter( CodingErrorAction.REPLACE); bytes.limit(0); } the Charset that defines the character converter
/** * Closes this reader. This implementation closes the source InputStream and * releases all local storage. * * @throws IOException * */ @Override public void close() throws IOException { synchronized (lock) { if (decoder != null) { decoder.reset(); } if an error occurs attempting to close this reader.
/** * Returns the historical name of the encoding used by this writer to convert characters to * bytes, or null if this writer has been closed. Most callers should probably keep * track of the String or Charset they passed in; this method may not return the same * name. */ public String getEncoding() { if (!isOpen()) { return null; } return HistoricalCharsetNames.get(decoder.charset()); }
/** * 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 * */ @Override public int read() throws IOException { synchronized (lock) { if (!isOpen()) { throw new IOException("InputStreamReader is closed"); } char[] buf = new char[1]; return read(buf, 0, 1) != -1 ? buf[0] : -1; } } if this reader is closed or some other I/O error occurs.
/** * 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 buffer * the array to store the characters read.
* @param offset * * the initial position in {@code buf} to store the characters read from this reader.
* @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 * */ @Override public int read(char[] buffer, int offset, int length) throws IOException { synchronized (lock) { if (!isOpen()) { throw new IOException("InputStreamReader is closed"); } if this reader is closed or some other I/O error occurs.
// bytes.remaining() indicates number of bytes in buffer // when 1-st time entered, it'll be equal to zero boolean needInput = !bytes.hasRemaining();
while (out.hasRemaining()) { // fill the buffer if needed if (needInput) { try { if (in.available() == 0 && out.position() > offset) { // we could return the result without blocking read break; } } catch (IOException e) { // available didn't work so just try the read }
if (actualByteCount == -1) { endOfInput = true; break; } else if (actualByteCount == 0) { break; } bytes.limit(bytes.limit() + actualByteCount); needInput = false; }
if (result.isUnderflow()) { // compact the buffer if no space left if (bytes.limit() == bytes.capacity()) { bytes.compact(); bytes.limit(bytes.position()); bytes.position(0); } needInput = true; } else {
break; } }
if (result == CoderResult.UNDERFLOW && endOfInput) { result = decoder.decode(bytes, out, true); decoder.flush(out); decoder.reset(); } if (result.isMalformed() || result.isUnmappable()) { result.throwException(); }
/** * 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 * */ @Override public boolean ready() throws IOException { synchronized (lock) { if (in == null) { throw new IOException("InputStreamReader is closed"); } try { return bytes.hasRemaining() || in.available() > 0; } catch (IOException e) { return false; } } } } if this reader is closed or some other I/O error occurs.