The use and principle analysis of BufferedInputStream

We usually read files. For example, using FileInputStream to read files is inefficient. Therefore, we can use BufferedInputStream to read files. The efficiency of reading files will be greatly improved. Here we introduce how to use BufferedInputStream and analyze its working principle

1, Introduction to use:

1.1 definition:

BufferedInputStream is a high-level stream. It cannot operate on files directly. Only low-level streams can be directly connected to files. Therefore, a low-level stream needs to be nested, for example:

FileInputStream fis = new FileInputStream("test.txt");

BufferedInputStream bis = new BufferedInputStream(fis);

 

1.2 read file:

When reading, we usually use the read() method to read in a circular way. If we read to the end of the file, the read() method will return - 1, for example:

 

int len = -1;
while((len=bis.read())!=-1){
    System.out.println(len);
}

 

 

 

Through circular reading, the file can be read

 

2, Principle analysis:

Learn how to use BufferedInputStream through the above content, and how does it work? The following will understand its working principle through the source code analysis of BufferedInputStream

2.1 first, analyze the properties and constructors of BufferedInputStream:

The properties are as follows:

//Default buffer size 8 k
private static int DEFAULT_BUFFER_SIZE = 8192;
/*Maximum buffer size Integer.MAX_VALUE - 8, minus 8 because the virtual machine keeps some header information in the array*/
private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
//Define buffer byte array of datastore
protected volatile byte buf[];
//Atomic property Updater,To ensure that buf Atomic update
private static final
        AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater =
        AtomicReferenceFieldUpdater.newUpdater
        (BufferedInputStream.class,  byte[].class, "buf");
//buf Size of actual data in byte array
protected int count;
//Where to start reading
protected int pos;
//Record where the last read started
protected int markpos = -1;
//Maximum advance reads allowed
protected int marklimit;

 

The constructor is as follows:

//with InputStream As a parameter,Buffer size default 8 k
public BufferedInputStream(InputStream in) {
        this(in, DEFAULT_BUFFER_SIZE);
}

//Custom buffer size
public BufferedInputStream(InputStream in, int size) {
        super(in);
        if (size <= 0) {
            throw new IllegalArgumentException("Buffer size <= 0");
        }
        buf = new byte[size];
}

 

2.2 method analysis:

2.2.1.read() method analysis:

//Parameterless read()method
public synchronized int read() throws IOException {
        //If the starting read position is greater than or equal to the actual buffer size
        if (pos >= count) {
            //Fill buffer
            fill();
            //After filling,Is the read location greater than or equal to the actual buffer size,Then reading is completed,return-1
            if (pos >= count)
                return -1;
        }
        //Returns the first byte in the buffer
        return getBufIfOpen()[pos++] & 0xff;
}

 

2.2.2.read1(byte[] b, int off, int len) method analysis:

This method can be used to customize the byte array, as well as the starting position and the actual reading length. The source code is as follows:

 

private int read1(byte[] b, int off, int len) throws IOException {
     //Readable size 
        int avail = count - pos;
        //If the readable size is less than or equal to 0
        if (avail <= 0) {
             //If len Greater than or equal to buffer size and tag position less than 0,Read according to the given length
             if (len >= getBufIfOpen().length && markpos < 0) {
                 return getInIfOpen().read(b, off, len);
             }
            //Otherwise read at default size
            fill();
             avail = count - pos;
             //If the readable size is less than or equal to,Then reading is completed,return-1
             if (avail <= 0) return -1;
         }
         //take avail and len The smaller of
         int cnt = (avail < len) ? avail : len;
         //Set the byte array of the buffer from the pos Position start,Count Reg cnt Copy content of to b In byte array off Where to start
         System.arraycopy(getBufIfOpen(), pos, b, off, cnt);
         //Read position increase cnt
         pos += cnt;
         //Returns the length of the read
         return cnt;
}

 

 

2.2.3.read(byte b[], int off, int len) method analysis:

public synchronized int read(byte b[], int off, int len)
        throws IOException
    {
        //Check whether the flow is closed
        getBufIfOpen(); // Check for closed stream
       //adopt"|"Operation assurance off,len Greater than or equal to 0,b.length Greater than or equal to off+len
        if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }
        int n = 0;
        //Infinite cycle,As long as the remaining content meets the length len,The length that can be read each time is len
        for (;;) {
            //read len Length bytes
            int nread = read1(b, off + n, len - n);
            if (nread <= 0)
                return (n == 0) ? nread : n;
            //Because the length of the buffer byte array is 8192,hypothesis len It's 800,After reading 10 times,The remaining length of buffer bytes is 192,The length of the first read is 192,n That's 192,here,No return,Will cycle again.When cycling again,Fill buffer first,Read the remaining 608,After reading 800,Then return the length of 800.
            n += nread;
            if (n >= len)
                return n;
            // if not closed but no bytes available, return
            InputStream input = in;
            //If the buffer available size in the input stream is less than or equal to 0,Then return n
            if (input != null && input.available() <= 0)
                return n;
        }
}

 

2.2.4.fill() method analysis:

The fill() method is used to read the data and fill the buffer

private void fill() throws IOException {
        //Check whether the flow is closed
        byte[] buffer = getBufIfOpen();
        //Judgment mark position is less than 0
        if (markpos < 0)
            //Set location to 0,Start position
            pos = 0;            /* no mark: throw away the buffer */
        //If the location is greater than or equal to the buffer size,Then proceed as follows
        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;
            } else if (buffer.length >= marklimit) {
                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;
            }
        //Set size to pos
        count = pos;
        //Read data of default size to buffer,And return the read length
        int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
        if (n > 0)
            //take count Set to length size
            count = n + pos;
} 

Tags: less

Posted on Thu, 21 May 2020 04:14:08 -0400 by godster