How to correctly use Java I/O to output and read data
PrefaceJava I/O systems use "streams" to process various types of input and output data tasks. In the process of data transmission, we need to determine when the data transmitted in the stream ends. This is critical for us to correctly send and receive data. How to judge the end of the stream and the end of the batch data is the key to solving this problem. This article aims to thoroughly analyze the working principles of Java I/O input and output, so that we can correctly send and receive data!
Java I/O tasksA Java I/O task creates a data transmission pipeline that connects two systems. It consists of two parts: input stream and output stream. An input stream refers to a one-way data transmission channel that transmits data to the memory of the system. An output stream refers to a one-way data transmission channel that transmits data to an external system.
Input stream
Inputstream
Class isIndicates the superclass of all classes in the byte input stream. This is an abstract class. We can see the Data Reading method provided by it:
Read
public abstract int read()
throws IOException
Reads the next Data byte from the input stream. Return
0To
255Within the scope
intByte value. If no byte is available because it has reached the end of the stream, the returned value is
-1. This method is always blocked until the input data is available, the end of the stream is detected, or an exception is thrown. Subclass must provide an implementation of this method.
Return Value:Next Data byte. If it reaches the end of the stream, return
-1.
Throw:
IOException-If an I/O error occurs.
Read
public int read(byte[] b)
throws IOException
Reads a certain number of bytes from the input stream and stores them in the buffer array.
b. Returns the actual number of bytes read as an integer. This method is always blocked until the input data is available, the end of the file is detected, or an exception is thrown. If
bIs
null, Will throw
NullPointerException. If
bIf the length is 0, no Bytes are readable and return
0Otherwise, try to read at least one byte. If the stream is at the end of the file and there are no available bytes, the returned value is
-1Otherwise, at least one byte can be read and stored in
b. Store the first byte read in the element
b[0]In
b[1]And so on. The maximum number of bytes read is equal
b. Let
KThe number of bytes actually read. These bytes are stored in the element
b[0]To
b[
K
-1]Does not affect elements.
b[
K
]To
b[b.length-1]. If the first byte cannot be read because the stream is not at the end of the file
IOException. In particular, if the input stream is disabled
IOException. Class
InputStreamOf
read(b)The effect of the method is equivalent:
read(b, 0, b.length)
Parameters:
b-Buffer for reading data.
Return Value:The total number of bytes read into the buffer. If no data exists because the end of the stream has arrived
-1.
Throw:
IOException-If an I/O error occurs.
NullPointerException-If
bIs
null.
For more information, see:
read(byte[], int, int)
Read
public int read(byte[] b,
int off,
int len)
throws IOException
Maximum number of input streams
lenData bytes are read into the byte array. Try to read up
lenBytes, but may read a small number. Returns the actual number of bytes read as an integer. This method is always blocked until the input data is available, the end of the stream is detected, or an exception is thrown. If
bIs
null, Then throw
NullPointerException. If
offIs negative, or
lenIs negative, or
off+lenGreater than Array
bWill throw
IndexOutOfBoundsException. If
lenIf the value is 0, no Bytes are readable and return
0Otherwise, try to read at least one byte. If the stream is at the end of the file and there are no available bytes, the returned value is
-1Otherwise, at least one byte can be read and stored in
b. Store the first byte read in the element
b[off]In
b[off+1]And so on. The maximum number of bytes read is equal
len. Let
KThe number of bytes actually read. These bytes are stored in the element
b[off]To
b[off+
K
-1]And other elements
b[off+
K
]To
b[off+len-1]Not affected. Element
b[0]To
b[off]And Element
b[off+len]To
b[b.length-1]Will not be affected. If the first byte cannot be read because the stream is not at the end of the file
IOException. In particular, if the input stream is disabled
IOException. Class
InputStreamOf
read(b,
off,
len)The method is called repeatedly.
read(). If the first such call causes
IOExceptionFrom
read(b,
off,
len)This exception is returned when a method is called. If
read()Any subsequent call
IOException, The exception will be caught and the location where the exception occurred will be considered as the end of the file; the bytes read at this point are stored in
bReturns the number of bytes read before an exception occurs. We recommend that subclass provide more effective implementation of this method.
Parameters:
b-Buffer for reading data.
off-The array where data is written
b.
len-Maximum number of bytes to read.
Return Value:The total number of bytes read into the buffer. If no data exists at the end of the stream
-1.
Throw:
IOException-If an I/O error occurs.
NullPointerException-If
bIs
null.
For more information, see:
read()
Read method explanationThe core of these methods. It is actually the read () method. The javadoc of this method indicates: "If no byte is available because it has reached the end of the stream, the returned value is
-1. If no byte is available because it has reached the end of the stream, the returned value is
-1. This method is blocked until the input data is available, the end of the stream is detected, or an exception is thrown ." 1. The read method will always block the thread before it can return the bytes in the stream. This means that the read method is a good method for low-consumption listening and reading I/O transmission. The implementation of this method has very high performance. 2. If the I/O system of the input stream throws an exception when executing this read method, it is clear that this method will end abnormally, which is undoubtedly true. 3. "If no byte is available because it has reached the end of the stream, the returned value is
-1." This sentence seems to be okay, but it is actually very ambiguous! What is the end of a stream? Can-1 be returned only at the end of a stream?
Source code explanation of inputstream and socketinputstreamBy looking at the source code of the inputstream class, I found that the stream is like a two-way, two-lane expressway. It transmits a batch of data. I call it "batch data ". Assume that a = B is connected by an I/O Stream. The lane from the B end to the end is called the "input stream" of ". The same lane, on the B side, is called the "output stream" of B ". Similarly, the lane from A to B is called the "output stream" of ". The same lane, on the B side, is called the "input stream" of B ". Data on this highway does not run one by one, but is run in batches.
Outputstream class,This abstract class is a super class that represents all the classes of the output byte stream. The output stream accepts the output bytes and sends them to a receiver.
The write method of the outputstream class sends a batch of data to the expressway every time it is executed. Some subclasses of the outputstream class do not send the data to the data highway immediately after each write () method execution. Instead, only after the flush () method is executed can multiple batches of previously written data be truly sent to the data channel.
In this way, the data sent by multiple write () methods is changed to a batch of Data!
When you read data using the read () method, if you execute the read () method again after reading the batch of data,-1 is returned immediately.
In fact, this is not at the end of the stream! Only a batch of sent data is read!
If we execute the read () method again, if:
1. the stream is not finished. That is to say, the opposite sender may block the next batch of data. The current thread is paused until the first byte of the next batch of data in the input stream is read.
2. the stream is finished. That is to say, the sender of the opposite side no longer sends any data, that is, this data channel is no longer in use. In this case, it can be said that "The end of the stream" is reached! -1 is returned.
Therefore, the comments of the read () method of inputstream and its subclass are incomplete!
The comment of the read () method should be said as follows:
Read
public abstract int read()
throws IOException
Reads the next Data byte from the input stream. Return
0To
255Within the scope
intByte value. If the read () method is called for the first time after reading a batch of data,-1 is returned. Indicates that this batch of data has been read! If no byte is available because it has reached the end of the stream, the returned value is
-1. This method is always blocked until the input data is available, the end of the stream is detected, or an exception is thrown. Subclass must provide an implementation of this method.
Return Value:Next Data byte;-1 is returned if a batch of data has just been read;-1 is returned if it reaches the end of the stream
-1.
Throw:
IOException-If an I/O error occurs.
How to correctly use Java I/O to output and read dataAfter understanding the execution results of Java I/O Stream and read methods, we can use the Java I/O system to output and read data correctly.
How to output data in batchesBecause read (...) The method is to read data in batches. Therefore, we should correctly output data in batches at the output end. Write (...) And then execute the flush () method to merge multiple batches of data into a batch of data output. Although the flush () method of the base class outputstream is useless, the output object of the outputstream type is a subclass object of the class, we should try to use the flush () method to force physical data output to the output stream to avoid errors.
How to read data in batches
Public int is often used.Read(Byte [] B,
Int off, int Len) throws ioexception to read a batch of data. Check the source code of this method. We can find that when reading a batch of data, it executes the read () method again. For the reasons described above, this method immediately returns-1, then exit this method and return the number of bytes read this time. Therefore, to read a batch of data, you can use the following methods:
Read a batch of data using read () judgment-1:Code example: int byte; while (byte = inputstream. Read ())! =-1) {byte is the returned byte. } If you run the read method again after reading a batch of data,-1 will be returned immediately, indicating that the batch of data has been read.
Read (byte [] buffer) is used to determine whether to return data smaller than buffer. length or-1 to determine whether to read a batch of data.Reading data one byte is troublesome. We usually use a byte array to read data. The read (byte [] buffer) method returns: 1, buffer. length, indicating that the data read from the input stream is full of this byte array. At this time, you may have read this batch of data, or you may not have read this batch of data. If you just read the data, execute the read () method again and return-1, indicating that the data has been read, rather than indicating that the stream has ended. 2, smaller than buffer. length. Indicates that the batch of data has been read. The read () method is executed and-1 is returned, indicating that the data has been read. 3,-1. This batch of data has been read. It cannot be that the stream has ended. Because the while loop will be exited before. Code example: byte [] buffer = new byte [1024]; int size = buffer. length; while (size! =-1 | size> = buffer. Length) {size = inputstream. Read (buffer); read data to the array buffer. If-1 is read, or the read data is smaller than the buffer size, it indicates that the batch of data has been read and data will not be read cyclically! }
Operations for reading a batch of data must correspond to operations for outputting a batch of dataThe operation for reading a batch of data must correspond to the operation for outputting a batch of data. Otherwise, the thread that reads data will be congested until the output end outputs the next batch of data. If the other party also needs to provide output data, it may cause the threads at both ends of the whole stream to wait for each other and deadlock. And the I/O Stream will never be released, which will exhaust the system resources.
Postscript:During my work two days ago, when I used socket to perform operations on the server and client, a deadlock occurred. To find out the root cause of the problem, I carefully checked the source code of the inputstream class and socketinputstream class. Find out the cause of misuse of input and output streams. I hope this article will help Java programmers who suffer from I/O input and output stream problems!