[go: up one dir, main page]

0% found this document useful (0 votes)
79 views12 pages

In Put Stream Reader

This class provides functionality for reading characters from an InputStream and converting bytes to characters using a CharsetDecoder. It contains a buffer that bytes are read into from the InputStream and decoded into characters as needed. It implements Reader and includes methods like read(), close(), and ready() to perform character reading and check readability. The constructor allows specifying the InputStream and Charset/CharsetDecoder to use for decoding bytes to characters.
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
79 views12 pages

In Put Stream Reader

This class provides functionality for reading characters from an InputStream and converting bytes to characters using a CharsetDecoder. It contains a buffer that bytes are read into from the InputStream and decoded into characters as needed. It implements Reader and includes methods like read(), close(), and ready() to perform character reading and check readability. The constructor allows specifying the InputStream and Charset/CharsetDecoder to use for decoding bytes to characters.
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 12

package java.

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;

private boolean endOfInput = false;

private CharsetDecoder decoder;

private final ByteBuffer bytes = ByteBuffer.allocate(8192);

/** * 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. *

* @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 * */ 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.

decoder = null; if (in != null) { in.close(); in = null; } } }

/** * 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.

* @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 * */ @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.

Arrays.checkOffsetAndCount(buffer.length, offset, length); if (length == 0) { return 0; }

CharBuffer out = CharBuffer.wrap(buffer, offset, length); CoderResult result = CoderResult.UNDERFLOW;

// 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 }

int desiredByteCount = bytes.capacity() - bytes.limit();

int off = bytes.arrayOffset() + bytes.limit(); int actualByteCount = in.read(bytes.array(), off, desiredByteCount);

if (actualByteCount == -1) { endOfInput = true; break; } else if (actualByteCount == 0) { break; } bytes.limit(bytes.limit() + actualByteCount); needInput = false; }

// decode bytes result = decoder.decode(bytes, out, 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(); }

return out.position() - offset == 0 ? -1 : out.position() - offset; } }

private boolean isOpen() { return in != null; }

/** * 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.

You might also like