English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Java IO BufferedInputStream
Summary:
BufferedInputStream is a buffered input stream, inheriting from FilterInputStream, which adds some features to another input stream, essentially implemented through an internal buffer array. For example, after creating a BufferedInputStream corresponding to a certain input stream, when data is read through read(), BufferedInputStream will batch the data from the input stream into the buffer. Whenever the data in the buffer is read out, the input stream will refill the buffer until the data is completely read.
List of main functions of BufferedInputStream:
BufferedInputStream(InputStream in) BufferedInputStream(InputStream in, int size) synchronized int available() void close() synchronized void mark(int readlimit) boolean markSupported() synchronized int read() synchronized int read(byte[] buffer, int offset, int byteCount) synchronized void reset() synchronized long skip(long byteCount)
Example code:
public class BufferedInputStreamTest { private static final int LEN = 5; public static void main(String[] args) { testBufferedInputStream() ; } private static void testBufferedInputStream() { // Create a BufferedInputStream byte stream, containing the ArrayLetters array try { File file = new File("file.txt"); InputStream in =new BufferedInputStream(new FileInputStream(file), 512); // Read from the byte stream5bytes. "abcde", a corresponds to 0x61, b corresponds to 0x62, and so on... for (int i=0; i<LEN; i++) { // If the next byte can be read, read the next byte if (in.available() >= 0) { // Read the next byte of the 'byte stream' int tmp = in.read(); System.out.printf("%d : 0x%s\n", i, Integer.toHexString(tmp)); } } // If the 'byte stream' does not support the marking function, exit directly if (!in.markSupported()) { System.out.println("make not supported!"); return ; } // Mark the 'current index position', that is, mark the position6elements at the position--"f" // 1024corresponding to marklimit in.mark(1024); // Skip22bytes. in.skip(22); // read5bytes byte[] buf = new byte[LEN]; in.read(buf, 0, LEN); // Convert buf to a String string. String str1 = new String(buf); System.out.printf("str1=%s\n", str1); // Reset the 'input stream index' to the position marked by mark(), that is, reset to the position 'f'. in.reset(); // Read from the "reset byte stream"5bytes into buf. That is, read "fghij" in.read(buf, 0, LEN); // Convert buf to a String string. String str2 = new String(buf); System.out.printf("str2=%s\n", str2); in.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
Running results:
0 : 0x61 1 : 0x62 2 : 0x63 3 : 0x64 4 : 0x65 str1=12345 str2=fghij
Based on JDK8The code of BufferInputStream:
public class BufferedInputStream extends FilterInputStream { private static int DEFAULT_BUFFER_SIZE = 8192;//Default buffer size is8X1024 private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8; protected volatile byte buf[]; //buffer array /** * Atomic updater to provide compareAndSet for buf. This is * necessary because closes can be asynchronous. We use nullness * of buf[] as the primary indicator that this stream is closed. (The * "in" field is also nulled out on close.) */ private static final AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater = AtomicReferenceFieldUpdater.newUpdater(BufferedInputStream.class, byte[].class, "buf"); //The value is between 0 and buf.len protected int count; //The next character to be read is at the current position in the buffer. protected int pos; //The value is the time when the mark function was last called, the value is-1to pos protected int markpos = -1; /** * The maximum read ahead allowed after a call to the * <code>mark</<code> method before subsequent calls to the * <code>reset</code> method fail. * Whenever the difference between <code>pos</code> * and <code>markpos</<code> exceeds <code>marklimit</<code>, * then the mark may be dropped by setting * <code>markpos</code> to <code>-1</code>. * * @see java.io.BufferedInputStream#mark(int) * @see java.io.BufferedInputStream#reset() */ protected int marklimit; /** * Check to make sure that underlying input stream has not been * nulled out due to close; if not return it; */ // private InputStream getInIfOpen() throws IOException { InputStream input = in; if (input == null) throw new IOException("Stream closed"); return input; } /** * Check to make sure that buffer has not been nulled out due to * close; if not return it; */ private byte[] getBufIfOpen() throws IOException { byte[] buffer = buf; if (buffer == null) throw new IOException("Stream closed"); return buffer; } /** * Creates a <code>BufferedInputStream</code> * and saves its argument, the input stream * <code>in</code>, for later use. An internal * buffer array is created and stored in <code>buf</code>. * * @param in the underlying input stream. */ //Constructor with InputStream public BufferedInputStream(InputStream in) { this(in, DEFAULT_BUFFER_SIZE); } /** * Creates a <code>BufferedInputStream</code> * with the specified buffer size, * and saves its argument, the input stream * <code>in</code>, for later use. An internal * buffer array of length <code>size</code> * is created and stored in <code>buf</code>. * * @param in the underlying input stream. * @param size the buffer size. * @exception IllegalArgumentException if size <= 0. */ //Constructor with InputStream and size public BufferedInputStream(InputStream in, int size) { super(in); if (size <= 0) { throw new IllegalArgumentException("Buffer size <= 0"); } buf = new byte[size]; } /** * Fills the buffer with more data, taking into account * shuffling and other tricks for dealing with marks. * Assumes that it is being called by a synchronized method. * This method also assumes that all data has already been read in, * hence pos > count. */ // private void fill() throws IOException { byte[] buffer = getBufIfOpen(); if (markpos < 0) pos = 0; /* no mark: throw away the buffer */ else if (pos >= buffer.length) /* no room left in buffer */ if (markpos > 0) { /* can throw away early part of the buffer */ int sz = pos - markpos; System.arraycopy(buffer, markpos, buffer, 0, sz); pos = sz; markpos = 0; } markpos = -1; /* buffer got too big, invalidate mark */ pos = 0; /* drop buffer contents */ } else if (buffer.length >= MAX_BUFFER_SIZE) { throw new OutOfMemoryError("Required array size too large"); } else { /* grow buffer */ int nsz = (pos <= MAX_BUFFER_SIZE - pos) ? pos * 2 : MAX_BUFFER_SIZE; if (nsz > marklimit) nsz = marklimit; byte nbuf[] = new byte[nsz]; System.arraycopy(buffer, 0, nbuf, 0, pos); if (!bufUpdater.compareAndSet(this, buffer, nbuf)) { // Can't replace buf if there was an async close. // Note: This would need to be changed if fill() // is ever made accessible to multiple threads. // But for now, the only way CAS can fail is via close. // assert buf == null; throw new IOException("Stream closed"); } buffer = nbuf; } count = pos; int n = getInIfOpen().read(buffer, pos, buffer.length - pos); if (n > 0) count = n + pos; } /** * See * the general contract of the <code>read</code> * method of <code>InputStream</code>/code>. * * @return the next byte of data, or <code>-1</code> if the end of the * stream is reached. * @exception IOException if this input stream has been closed by * invoking its {@link #close()} method, * or an I/O error occurs. * @see java.io.FilterInputStream#in */ //read the next byte, return if no data is available-1 public synchronized int read() throws IOException { if (pos >= count) { fill(); if (pos >= count) return -1; } return getBufIfOpen()[pos++] & 0xff; } /** * Read characters into a portion of an array, reading from the underlying * stream at most once if necessary. */ private int read1(byte[] b, int off, int len) throws IOException { int avail = count - pos; if (avail <= 0) { /* If the requested length is at least as large as the buffer, and if there is no mark/reset activity, do not bother to copy the bytes into the local buffer. In this way buffered streams will harmlessly cascade. */ if (len >= getBufIfOpen().length && markpos < 0) { return getInIfOpen().read(b, off, len); } fill(); avail = count - pos; if (avail <= 0) return -1; } int cnt = (avail < len) ?63; avail : len; System.arraycopy(getBufIfOpen(), pos, b, off, cnt); pos += cnt; return cnt; } /** * Reads bytes from this byte-input stream into the specified byte array, * starting at the given offset. * * <p> This method implements the general contract of the corresponding * code> method of <code>{@link InputStream#read(byte[], int, int) read}</code> method of * the <code>{@link InputStream}</code> class. As an additional * convenience, it attempts to read as many bytes as possible by repeatedly * invoking the <code>read</code> method of the underlying stream. This * iterated <code>read</code> continues until one of the following * conditions becomes true: <ul> * * <li> The specified number of bytes have been read, * * <li> The <code>read</code> method of the underlying stream returns * <code>-1</code>, indicating end-of-file, or * * <li> The <code>available</code> method of the underlying stream * returns zero, indicating that further input requests would block. * * </ul> If the first <code>read</code> on the underlying stream returns * <code>-1</code> to indicate end-of-file then this method returns * <code>-1</code>. Otherwise this method returns the number of bytes * actually read. * * <p> Subclasses of this class are encouraged, but not required, to * attempt to read as many bytes as possible in the same fashion. * * @param b destination buffer. * @param off offset at which to start storing bytes. * @param len maximum number of bytes to read. * @return the number of bytes read, or <code>-1</code> if the end of * the stream has been reached. * @exception IOException if this input stream has been closed by * invoking its {@link #close()} method, * or an I/O error occurs. */ // public synchronized int read(byte b[], int off, int len) throws IOException { getBufIfOpen(); // Check for closed stream if ((off | len | (off + len) | (b.length - (off + ((off < 0) || (len < 0) || (off > len))) < 0) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } int n = 0; for (;;) { int nread = read1(b, off + n, len - n); if (nread <= 0) return (n == 0) &63; nread : n; n += nread; if (n >= len) return n; // if not closed but no bytes available, return InputStream input = in; if (input != null && input.available() <= 0) return n; } } /** * See the general contract of the <code>skip</code> method./code> * method of <code>InputStream</code>/code>. * * @exception IOException if the stream does not support seek, * or if this input stream has been closed by * invoking its {@link #close()} method, or an * I/O error occurs. */ //Skip data of length n public synchronized long skip(long n) throws IOException { getBufIfOpen(); // Check for closed stream if (n <= 0) { return 0; } long avail = count - pos; if (avail <= 0) { // If no mark position set then don't keep in buffer if (markpos < 0) return getInIfOpen().skip(n); // Fill in buffer to save bytes for reset fill(); avail = count - pos; if (avail <= 0) return 0; } long skipped = (avail < n) ?63; avail : n; pos += skipped; return skipped; } /** * Returns an estimate of the number of bytes that can be read (or * skipped over) from this input stream without blocking by the next * invocation of a method for this input stream. The next invocation might be * the same thread or another thread. A single read or skip of this * Many bytes will not block, but may read or skip fewer bytes. * <p> * This method returns the sum of the number of bytes remaining to be read in * the buffer (<code>count - pos</code>) and the result of calling the * {@link java.io.FilterInputStream#in in}.available(). * * @return an estimate of the number of bytes that can be read (or skipped * over) from this input stream without blocking. * @exception IOException if this input stream has been closed by * invoking its {@link #close()} method, * or an I/O error occurs. */ //Returns how many data can be read public synchronized int available() throws IOException { int n = count - pos; int avail = getInIfOpen().available(); return n > (Integer.MAX_VALUE - avail)? Integer.MAX_VALUE: n + avail; } /** * See the general contract of the <code>mark</code> method./code> * method of <code>InputStream</code>/code>. * * @param readlimit the maximum limit of bytes that can be read before * the mark position becomes invalid. * @see java.io.BufferedInputStream#reset() */ public synchronized void mark(int readlimit) { marklimit = readlimit; markpos = pos; } /** * See the general contract of the <code>reset</code> method./code> * method of <code>InputStream</code>/code>. * <p> * If <code>markpos</code>/code> is <code>-1</code> * (no mark has been set or the mark has been * invalidated), an <code>IOException</code>/code> * is thrown. Otherwise, <code>pos</code>/code> is * set equal to <code>markpos</code>/code>. * * @exception IOException if this stream has not been marked or, * if the mark has been invalidated, or the stream * has been closed by invoking its {@link #close()} * method, or an I/O error occurs. * @see java.io.BufferedInputStream#mark(int) */ public synchronized void reset() throws IOException { getBufIfOpen(); // Cause exception if closed if (markpos < 0) throw new IOException("Resetting to invalid mark"); pos = markpos; } /** * Tests if this input stream supports the <code>mark</code>/code> * and <code>reset</code>/code> methods. The <code>markSupported</code>/code> * method of <code>BufferedInputStream</code>/code> returns * <code>true</code>/code>. * * @return a <code>boolean</code>/code> indicating if this stream type supports * the <code>mark</code>/code> and <code>reset</code>/code> methods. * @see java.io.InputStream#mark(int) * @see java.io.InputStream#reset() */ //Whether it supports marking public boolean markSupported() { return true; } /** * Closes this input stream and releases any system resources * associated with the stream. * Once the stream has been closed, further read(), available(), reset(), * or skip() invocations will throw an IOException. * Closing a previously closed stream has no effect. * * @exception IOException if an I/O error occurs. */ //Close Resources public void close() throws IOException { byte[] buffer; while ( (buffer = buf) != null) { if (bufUpdater.compareAndSet(this, buffer, null)) { InputStream input = in; in = null; if (input != null) input.close(); return; } // Else retry in case a new buf was CASed in fill() } } }
Thank you for reading, I hope it can help everyone. Thank you for your support to this site!