Streams and buffers
Buffer is a container containing a certain amount of data. Some people think that a stream is a buffer, but it's not. A stream is a data sequence generated over time, and the buffer, as its name implies, plays a buffer role. The essence of buffer is queuing, and the essence of stream is data. The buffer can be understood as a water pipe that meets FIFO. If we do not set the buffer, it will increase the instability and security of the system. For example, in the process of system docking, no buffer is set, and the requests made by other systems have to be responded immediately. They are tired until the system crashes. The cost of adding buffer is low, it can be processed in batch, and the effect is better.
In Java, the data stream we are familiar with mainly includes four basic classes, InputStream, OutputStream, Reader and Writer, which deal with byte stream and character stream respectively. Next, we will be familiar with the difference and use of stream and buffer through the examples of file writing and reading.
File read and write
When reading files, we can read files by bytes through FileInputStream (inheriting the InputStream abstract class), which is suitable for reading all types of files (images, videos, text files, etc.). Java also provides FileReader to read text files.
Fileoutputstream (inheriting the abstract class of OutputStream) writes data to files in bytes, which is suitable for all types of files. Java also provides FileWriter for writing text files.
Random random=new Random(); String fileName="word"; FileOutputStream out=new FileOutputStream(fileName); long start=System.currentTimeMillis(); for(int i=0;i<1000000;i++){ for(int j=0;j<5;j++){ out.write(97+random.nextInt(5)); } } out.close(); // Write output time in this way: 13765 ms System.out.println(System.currentTimeMillis()-start);
String fileName="word"; FileInputStream in=new FileInputStream(fileName); long start=System.currentTimeMillis(); while(in.read()!=-1){ } in.close(); // Read output time in this way: 9705ms System.out.println(System.currentTimeMillis()-start);
Buffered byte stream
When files or other data sources are read and written frequently, the efficiency is relatively low. At this time, if the buffer stream is used, the information can be read and written more efficiently. Because the buffer stream caches the data first, and then reads it to the program or writes it to the destination at one time when the cache is full or refreshed manually. BufferedInputStream and BufferedOutputStream are buffered byte streams. The efficiency of the operation stream is improved through the internal cache array.
Next, we optimize the above read and write codes by buffering the byte stream to see how fast they can be improved:
Random random=new Random(); String fileName="word"; // The buffer size can be set, and the default value of 8192 is not set int bufferSize=8*1024; BufferedOutputStream out=new BufferedOutputStream(new FileOutputStream(fileName),bufferSize); //FileOutputStream out=new FileOutputStream(fileName); long start=System.currentTimeMillis(); for(int i=0;i<1000000;i++){ for(int j=0;j<5;j++){ out.write(97+random.nextInt(5)); } } out.close(); // Write output time in this way: 246 ms System.out.println(System.currentTimeMillis()-start);
Random random=new Random(); String fileName="word"; BufferedInputStream in=new BufferedInputStream(new FileInputStream(fileName)); //FileInputStream in=new FileInputStream(fileName); long start=System.currentTimeMillis(); while(in.read()!=-1){ } in.close(); // Read output time in this way: 206ms System.out.println(System.currentTimeMillis()-start);
By comparing the execution speed of the two, it is found that the speed increases significantly. When reading, we can also actively set the Buffer instead of Buffer, as shown below:
FileInputStream in=new FileInputStream(fileName); byte[] bytes=new byte[1024*4]; while(in.read(bytes)!=-1){ }
NIO implementation buffer
Of course, we can also implement it through NIO, which literally means NEW IO. A NEW IO read and write standard. If you say whether the speed is different from the Buffer above, I can only say that there is no difference. However, a set of standards is provided below. We should set the Buffer according to its standards. Based on the code read above, the implementation is as follows:
String fileName="word"; // Get channel FileChannel channel=new FileInputStream(fileName).getChannel(); // Set buffer ByteBuffer buff=ByteBuffer.allocate(4*1024); long start=System.currentTimeMillis(); while(channel.read(buff)!=-1){ // Flip provides read buff.flip(); //System.out.println(new String(buff.array())); // empty buff.clear(); } // In this way, the read return time is 26ms System.out.println(System.currentTimeMillis()-start);
The above method and emptying may be difficult to understand. We can take a look at the specific implementation principle of buffer.
The implementation structure of a one-way buffer is as follows:
P. L and C respectively represent that the pointer points to the current position, the actual limit position and the physical limit position.
During the flip operation, we can find that P points to the starting position again, and L points to the back of the last letter, indicating that it can be read, while the clear operation points to the starting position, so that L points to the C position, which can be replaced.
Therefore, through the above methods to operate the pointer to modify the buffer.