Java 7 source code analysis 13th-byte input/output stream (1)

Source: Internet
Author: User

The previous article introduced the Java class framework of the byte input/output stream and briefly introduced the functions of each class. The following describes how these classes implement these functions.


1. InputStream and OutputStream


The source code of the InputStream class is as follows:

Public abstract class InputStream implements Closeable {private static final int MAX_SKIP_BUFFER_SIZE = 2048; // The maximum number of bytes can be skipped. // get the next byte and return the int value (range: 0 ~ 255). If the stream ends,-1 public abstract int read () throws IOException; public int read (byte B []) throws IOException {// read a byte, the returned value is the read byte return read (B, 0, B. length);} // read len bytes and place them in the following off-start byte array B. The returned value is the actual number of bytes read. public int read (byte B [], int off, int len) throws IOException {if (B = null) {throw new NullPointerException ();} else if (off <0 | len <0 | len> B. length-off) {throw new IndexOutOfBoun DsException ();} else if (len = 0) {return 0;} int c = read (); if (c =-1) {return-1 ;} B [off] = (byte) c; int I = 1; try {for (; I <len; I ++) {c = read (); if (c =-1) {break;} B [off + I] = (byte) c ;}} catch (IOException ee) {} return I ;} // The read pointer skips n Bytes and does not read. The returned value is the number of bytes actually skipped. public long skip (long n) throws IOException {long remaining = n; int nr; if (n <= 0) {return 0;} int size = (int) Ma Th. min (MAX_SKIP_BUFFER_SIZE, remaining); byte [] skipBuffer = new byte [size]; while (remaining> 0) {nr = read (skipBuffer, 0, (int) Math. min (size, remaining); if (nr <0) {break;} remaining-= nr;} return n-remaining ;} // The returned value is the number of unread bytes in the stream. This method should overwrite the public int available () throws IOException {return 0;} public void close () throws IOException {} // records the position of the current pointer. // The readlimit parameter indicates the readlim read by the read pointer. The pointer position marked after it bytes is effective. Public synchronized void mark (int readlimit) {}// point the read pointer back to the position recorded by the mark method public synchronized void reset () throws IOException {throw new IOException ("mark/reset not supported");} // whether the current stream supports the read pointer record function public boolean markSupported () {return false ;}}

To explain the mark () and reset () methods, as shown in.


Detailed explanations will be given to specific classes.

The source code of InputStream is as follows: <喎?http: www.bkjia.com kf ware vc " target="_blank" class="keylink"> VcD4KPHA + PC9wPgo8cHJlIGNsYXNzPQ = "brush: java;"> public abstract class OutputStream implements Closeable, flushable {/** The byte to be written is the eight low-order bits of the argument B. the 24 * high-order bits of B are ignored. */public abstract void write (int B) throws IOException; public void write (byte B []) throws IOException {write (B, 0, B. length);} public void write (byte B [], int off, int len) throws IOException {if (B = null) {throw new NullPointerException ();} else if (off <0) | (off> B. length) | (len <0) | (off + len)> B. length) | (off + len) <0) {throw new IndexOutOfBoundsException ();} else if (len = 0) {return ;} for (int I = 0; I <len; I ++) {write (B [off + I]) ;}} public void flush () throws IOException {} public void close () throws IOException {}}The above is mainly to write bytes into the output stream. The specific write method (int B) is an abstract method, depending on the implementation of the specific implementation class.


2. PipedInputStream and PipedOutputStream

The PipedInputStream and PipedOutputStream classes are used to create pipeline communication in applications. A PipedInputStream instance object must be connected to a PipedOutputStream instance object to generate a communication pipeline. pipedOutputStream can write data to the pipeline, and PipedIntputStream can read the data written by PipedOutputStream to the pipeline. these two classes are mainly used to complete the communication between threads. the PipedInputStream object of one thread can read data from the PipedOutputStream object of another thread.
The implementation principles of PipedInputStream and PipedOutputStream are similar to those of "producer-consumer". PipedOutputStream is the producer and PipedInputStream is the consumer. In PipedInputStream, there is a buffer byte array. The default size is 1024, store the things produced by the "producer. there are two variables in and out. In is used to record the amount produced by the "producer", out is used to record the amount consumed by the "consumer", in is-1 indicates that the consumption is complete, in = out indicates that the production is full. when the consumer has nothing to consume, that is, when the in is-1, the consumer will wait until something can be consumed.
In the constructor, the constructor provides the constructor for receiving the peer pipeline instance, and then calls the respective connect () method for connection, such as PipedInputStream:

    //  PipedInputStream    public PipedInputStream(PipedOutputStream src, int pipeSize)            throws IOException {         initPipe(pipeSize);         connect(src);    }    private void initPipe(int pipeSize) {         if (pipeSize <= 0) {            throw new IllegalArgumentException("Pipe Size <= 0");         }         buffer = new byte[pipeSize];    }    public void connect(PipedOutputStream src) throws IOException {        src.connect(this);    }
You can also specify the buffer size to see PipedOutputStream:

private PipedInputStream sink;    public PipedOutputStream(PipedInputStream snk)  throws IOException {        connect(snk);    }    public PipedOutputStream() {    }    //  PipedOutputStream    public synchronized void connect(PipedInputStream snk) throws IOException {        if (snk == null) {            throw new NullPointerException();        } else if (sink != null || snk.connected) {            throw new IOException("Already connected");        }        sink = snk;        snk.in = -1;        snk.out = 0;        snk.connected = true;    }

There is no rule for WHO to connect. As long as the connection is established, the effect is the same. The write () method in the output pipeline is as follows:

 public void write(int b)  throws IOException {        if (sink == null) {            throw new IOException("Pipe not connected");        }        sink.receive(b);    }    public void write(byte b[], int off, int len) throws IOException {        if (sink == null) {            throw new IOException("Pipe not connected");        } else if (b == null) {            throw new NullPointerException();        } else if ((off < 0) || (off > b.length) || (len < 0) ||                   ((off + len) > b.length) || ((off + len) < 0)) {            throw new IndexOutOfBoundsException();        } else if (len == 0) {            return;        }        sink.receive(b, off, len);    }
After the method is written to the byte [] array cache, The receive method in the output pipeline is called. The receive () method in the output pipeline is as follows:
/*** Es a byte of data. this method will block if no input is * available. */protected synchronized void receive (int B) throws IOException {checkStateForReceive (); writeSide = Thread. currentThread (); if (in = out) // in = out implies the buffer is full awaitSpace (); if (in <0) {// No data in the input pipeline in = 0; out = 0;} buffer [in ++] = (byte) (B & 0xFF); if (in> = buffer. length) {in = 0; // the buffer is full, waiting for the next write from scratch}/*** starts es data into an array of bytes. this method will * block until some input is available. */synchronized void receive (byte B [], int off, int len) throws IOException {checkStateForReceive (); writeSide = Thread. currentThread (); int bytesToTransfer = len; while (bytesToTransfer> 0) {if (in = out) awaitSpace (); int nextTransferAmount = 0; if (out <in) {nextTransferAmount = buffer. length-in;} else if (in <out) {if (in =-1) {in = out = 0; nextTransferAmount = buffer. length-in;} else {nextTransferAmount = out-in;} if (nextTransferAmount> bytesToTransfer) nextTransferAmount = bytesToTransfer; assert (nextTransferAmount> 0. arraycopy (B, off, buffer, in, nextTransferAmount); bytesToTransfer-= nextTransferAmount; off ++ = nextTransferAmount; in ++ = nextTransferAmount; if (in> = buffer. length) {in = 0 ;}}}
After the input management receives the data through the corresponding method above and saves it to the input buffer, you can use the read () method to read the data as follows:

    public synchronized int read()  throws IOException {        if (!connected) {            throw new IOException("Pipe not connected");        } else if (closedByReader) {            throw new IOException("Pipe closed");        } else if (writeSide != null && !writeSide.isAlive()                   && !closedByWriter && (in < 0)) {            throw new IOException("Write end dead");        }        readSide = Thread.currentThread();        int trials = 2;        while (in < 0) {            if (closedByWriter) {                /* closed by writer, return EOF */                return -1;            }            if ((writeSide != null) && (!writeSide.isAlive()) && (--trials < 0)) {                throw new IOException("Pipe broken");            }            /* might be a writer waiting */            notifyAll();            try {                wait(1000);            } catch (InterruptedException ex) {                throw new java.io.InterruptedIOException();            }        }        int ret = buffer[out++] & 0xFF;        if (out >= buffer.length) {            out = 0;        }        if (in == out) {            /* now empty */            in = -1;        }        return ret;    }    /**     * Reads up to len bytes of data from this piped input stream into an array of bytes. Less than len bytes     * will be read if the end of the data stream is reached or if len exceeds the pipe's buffer size.     * If len  is zero, then no bytes are read and 0 is returned;otherwise, the method blocks until     * at least 1 byte of input is available, end of the stream has been detected, or an exception is     */    public synchronized int read(byte b[], int off, int len)  throws IOException {        if (b == null) {            throw new NullPointerException();        } else if (off < 0 || len < 0 || len > b.length - off) {            throw new IndexOutOfBoundsException();        } else if (len == 0) {            return 0;        }        /* possibly wait on the first character */        int c = read();        if (c < 0) {            return -1;        }        b[off] = (byte) c;        int rlen = 1;        while ((in >= 0) && (len > 1)) {            int available;            if (in > out) {                available = Math.min((buffer.length - out), (in - out));            } else {                available = buffer.length - out;            }            // A byte is read beforehand outside the loop            if (available > (len - 1)) {                available = len - 1;            }            System.arraycopy(buffer, out, b, off + rlen, available);            out += available;            rlen += available;            len -= available;            if (out >= buffer.length) {                out = 0;            }            if (in == out) {                /* now empty */                in = -1;            }        }        return rlen;    }
The following is an example:
Public class test04 {public static void main (String [] args) {Sender sender = new Sender (); extends er extends ER = new extends Er (); PipedOutputStream outStream = sender. getOutStream (); PipedInputStream inStream = cycler. getInStream (); try {// inStream. connect (outStream); // same as the next sentence outStream. connect (inStream);} catch (Exception e) {e. printStackTrace ();} sender. start (); worker er. start () ;}} class Sender extends Thread {private PipedOutputStream outStream = new PipedOutputStream (); public PipedOutputStream getOutStream () {return outStream;} public void run () {String info = "hello, Cycler"; try {outStream. write (info. getBytes (); outStream. close ();} catch (Exception e) {e. printStackTrace () ;}} class extends er extends Thread {private PipedInputStream inStream = new PipedInputStream (); public PipedInputStream getInStream () {return inStream;} public void run () {byte [] buf = new byte [1024]; try {int len = inStream. read (buf); System. out. println ("receive message from sender:" + new String (buf, 0, len); inStream. close ();} catch (Exception e) {e. printStackTrace ();}}}
The output result is as follows: receive message from sender: hello, Cycler


3. ByteArrayInputStream and ByteArrayOutputStream

First, let's look at the write () method in the ByteArrayOutputStream class:

 // Writes the specified byte to this byte array output stream.    public synchronized void write(int b) {        ensureCapacity(count + 1);        buf[count] = (byte) b;        count += 1;    }    /**     * Writes len bytes from the specified byte array     * starting at offset off to this byte array output stream.     */    public synchronized void write(byte b[], int off, int len) {        if ((off < 0) || (off > b.length) || (len < 0) ||            ((off + len) - b.length > 0)) {            throw new IndexOutOfBoundsException();        }        ensureCapacity(count + len);        System.arraycopy(b, off, buf, count, len);        count += len;    }
This class is also passed by specifying the value in the array. The size of the byte array can be specified by the constructor when ByteArrayOutputStream is created. The default size is 32. if you call the write () method, the capacity of the byte array is guaranteed. If it is too small, the system automatically scales up. In this way, you can write the required data to the byte array. You can also write data to other output streams by calling the writeTo () method. The source code is as follows:

 /**     * Writes the complete contents of this byte array output stream to     * the specified output stream argument, as if by calling the output     * stream's write method using out.write(buf, 0, count).     */    public synchronized void writeTo(OutputStream out) throws IOException {        out.write(buf, 0, count);    }

Continue to see the ByteArrayInputStream class. This class can read data from byte arrays. The specific source code is as follows:

 public synchronized int read() {        return (pos < count) ? (buf[pos++] & 0xff) : -1;    }    public synchronized int read(byte b[], int off, int len) {        if (b == null) {            throw new NullPointerException();        } else if (off < 0 || len < 0 || len > b.length - off) {            throw new IndexOutOfBoundsException();        }        if (pos >= count) {            return -1;        }        int avail = count - pos;        if (len > avail) {            len = avail;        }        if (len <= 0) {            return 0;        }        System.arraycopy(buf, pos, b, off, len);        pos += len;        return len;    }
At the same time, other methods are provided, such as the skip () method for reading bytes and the avaible () method for viewing the remaining valid bytes. If you are interested, you can view them on your own. The following is an example of a specific application:

Byte [] bytes = {0, 2, 3, 4, 5}; try (ByteArrayOutputStream out = new ByteArrayOutputStream (); ByteArrayInputStream in = new ByteArrayInputStream (bytes);) {out. write (bytes); System. out. println (out. size (); // 5System. out. println (in. read (); // resolves in. skip (1); // 2in. mark (4); System. out. println (in. read (); // 3in. reset (); // read the System again from the index of 2. out. println (in. read (); // 3 System. out. println (in. read ();} catch (IOException e) {e. printStackTrace ();}

4. StringBufferInputStream

This class is no longer recommended. I think it is because of encoding. View the source code of this class, as shown below:

 public synchronized int read() {        return (pos < count) ? (buffer.charAt(pos++) & 0xFF) : -1;    }     public synchronized int read(byte b[], int off, int len) {        if (b == null) {            throw new NullPointerException();        } else if ((off < 0) || (off > b.length) || (len < 0) ||                   ((off + len) > b.length) || ((off + len) < 0)) {            throw new IndexOutOfBoundsException();        }        if (pos >= count) {            return -1;        }        if (pos + len > count) {            len = count - pos;        }        if (len <= 0) {            return 0;        }        String  s = buffer;        int cnt = len;        while (--cnt >= 0) {            b[off++] = (byte)s.charAt(pos++);        }        return len;    }

Found, in fact, this class is to convert the character in the string into bytes to read, if the character of this string is all ISO-8859-1 encoding can represent, it will certainly be able to read normally. However, Java is generally Unicode encoded and contains two characters. Therefore, if a Unicode character, such as Chinese, is displayed, the read will be inaccurate. Example:

String str = "Ma Zhi AB"; StringBufferInputStream st = new StringBufferInputStream (str); byte [] j = new byte [16]; st. read (j); System. out. println (new String (j); // lzAB
The cause may be unknown. The two read () methods obtain the character string (s. after charAt (), it is forcibly converted to byte or 0xff. Such a result can only result in 8-bit low encoding. For Chinese characters encoded in two bytes, it will certainly produce errors.










































































Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.