Research on ByteArrayOutputStream

This is a piece of code that reads and outputs an input stream

  Resource classPathResource = new ClassPathResource("1.txt");
  InputStream inputStream = pathResource.getInputStream();
  ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
  int i;
  while ((i=inputStream.read())!=-1){
    byteArrayOutputStream.write(i);
  }
  System.out.println(byteArrayOutputStream.toString());

The output data is as follows:

I have always had insufficient understanding of such a while loop in the past. Today, I suddenly wrote such a code again, so I wanted to study it in depth.

inputStream.read()

The official definition of this method is as follows

    /**
     * Reads the next byte of data from the input stream. The value byte is
     * returned as an <code>int</code> in the range <code>0</code> to
     * <code>255</code>. If no byte is available because the end of the stream
     * has been reached, the value <code>-1</code> is returned. This method
     * blocks until input data is available, the end of the stream is detected,
     * or an exception is thrown.
     *
     * <p> A subclass must provide an implementation of this method.
     *
     * @return     the next byte of data, or <code>-1</code> if the end of the
     *             stream is reached.
     * @exception  IOException  if an I/O error occurs.
     */
    public abstract int read() throws IOException;

That is to say, read the next byte of data from the input stream, and return the byte value of type int, the value of this byte ranges from 0 to 255. Returns -1 if the input stream has been read.

Let's talk about the knowledge of byte first.

byte

bit : Bit. A bit is the smallest unit of data in an electronic computer. The state of each bit can only be 0 or 1. Bill Gates once said that the computer world is made up of 0s and 1s. Computers can only read binary data such as 0 and 1.

byte : bytes. 8 binary bits constitute 1 "byte (Byte)", which is the basic unit of measurement of storage space. That is: 1byte=8bit.

Coding : The amount of coding knowledge is too large, here is just a brief mention of the utf-8 coding commonly used in development. In utf-8 encoding, one English character is equal to one byte, and one Chinese character (including traditional Chinese) is equal to three bytes. Both Chinese and English are called characters . Chinese punctuation occupies three bytes, and English punctuation occupies one byte. That is to say, a "thousand" word, which needs to be recognized by the computer, is first converted into three bytes corresponding to it (corresponding rules are in the relevant mapping table), and then converted into 3*8=24 (bit). The final result is 11100101 10001101 10000011 , a binary number that can only be read by a computer. The conversion of the English letter "Q" is simpler, it only needs one byte to represent 10000001.

Here is an address for online conversion of utf-8 encoding http://www.mytju.com/classcode/tools/encode_utf8.asp

streaming in java

During the development process, the stream transmission and data transmission I encountered basically used byte arrays, so I mainly talk about this here. From the first code of the article, it is not difficult to see that inputStream.read() assigns the binary data of the read file 1.txt to the variable i, and ByteArrayOutputStream is responsible for recording the value of i through the write() method, and then Use the toString() method to re-encode the recorded data for output. Here's a look at the underlying source code of ByteArrayOutputStream, put the important methods up, and annotated Chinese comments:

public class ByteArrayOutputStream extends OutputStream {

    /**
     *  byte数组,用于存储读取到的byte字节。
     */
    protected byte buf[];

    /**
     * 有效字节数
     */
    protected int count;

    /**
     * 初始化byte[] 数组,32长度
     */
    public ByteArrayOutputStream() {
        this(32);
    }

    public ByteArrayOutputStream(int size) {
        if (size < 0) {
            throw new IllegalArgumentException("Negative initial size: "
                                               + size);
        }
        buf = new byte[size];
    }

    /**
     * byte数组扩容,这是为了防止传入的数据量大于byte[]初始容量
     * */
    private void ensureCapacity(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - buf.length > 0)
            grow(minCapacity);
    }

    /**
     * 定义byte数组最大容量
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;


    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = buf.length;
        int newCapacity = oldCapacity << 1;
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        buf = Arrays.copyOf(buf, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

    /**
     * 把读取的一个字节放入byte[]
     */
    public synchronized void write(int b) {
        ensureCapacity(count + 1);
        buf[count] = (byte) b;
        count += 1;
    }


    /**
     * 将byte[]数组中存储的字节以平台默认编码(这里是utf-8)重新编码,并返回String类型的数据,也就是文本的内容。
     */
    public synchronized String toString() {
        return new String(buf, 0, count);
    }

Source code idea : define a byte[] variable to store all read bytes as a buffer field. This buffer area keeps growing as the object continues to read in data. When the amount of data is larger than the space of the buffer area, the buffer area will be expanded. When all the data is read into the buffer, the content inside is probably like this, buf[]={117,115,101,114...}. Finally, the data in the buffer is output again in a specific encoding by calling the toString() method.

Talk about a few key points in the source code:

  1.  int newCapacity = oldCapacity << 1; This means that the array space is doubled. oldCapacity is shifted to the left by one bit, that is, the left high bit is removed, and the right bit is filled with 0. Example: The binary representation of decimal 8 is 0000 1000 shifted left by 1 bit, 8<<1, becomes 0001 0000. Converted to decimal again, it becomes 16. This completes the expansion.
  2. new String(buf, 0, count) means that the character array buf starts from the first character (java starts with 0, or it can be said to be the 0th character), and builds all characters of length count into a string, also is String. This method helps us complete the conversion from bytes to characters.

 

From this point of view, this ByteArrayOutputStream is actually very simple. I also wrote a tool class here that outputs text data according to the input stream. It turned out that the code was really similar, so I encapsulated it a little.

/**
 *  千里明月
 */
public class OutputStreamUtil {
        private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
        private static int count=0;
        private static byte[] bytes=new byte[10];

        public static String write(InputStream inputStream) throws IOException {
            int i =0 ;
            while ((i=inputStream.read())!=-1){
                write(i);
            }
            return encode();
        }

        public static void write(int i){
            if (bytes.length<=count){
                grow(count+1);
            }
            bytes[count]= (byte) i;
            System.out.print(bytes[count]);
            count++;
        }

         private static void grow(int capacity) {
            int oldcapacity= bytes.length;
            int newcapacity= oldcapacity<<1;
             if (newcapacity<capacity){
                 newcapacity=capacity;
             }
             if (newcapacity<MAX_ARRAY_SIZE){
                 bytes = Arrays.copyOf(bytes, newcapacity);
             }
         }

        public static String encode(){
            return new String(bytes,0,count);
        }

}

Test class:

public class TestResource {

    public static void main(String[] args) throws IOException {

        Resource classPathResource = new ClassPathResource("1.txt");
        InputStream inputStream = classPathResource.getInputStream();
        String write = OutputStreamUtil.write(inputStream);
        System.out.println(write);
        inputStream.close();
    }
}

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325431580&siteId=291194637
Recommended