File I/O source code--Pipe 相关方法阅读

来源:互联网 发布:水果连连看软件 编辑:程序博客网 时间:2024/06/10 10:38

在java I/O把Inter-Thread Communication(线程之间的访问)称之为Pipe(管道),所以我们在使用PipedInputStream、PipedOutputStream、PipedWriter、PipedReader的时候都是和线程结合着使用,这里我们介绍一下PipedWriter和PipedReader相关方法,例子:

import java.io.IOException;import java.io.PipedReader;import java.io.PipedWriter;public class PipeExample {    public static void main(String[] args) throws IOException {        final PipedWriter writer = new PipedWriter();        final PipedReader reader = new PipedReader(writer);                Thread thread3 = new Thread(new Runnable() {@Overridepublic void run() {try {writer.write("Hello piped!");writer.close();} catch (IOException e) {e.printStackTrace();}}});                Thread thread4 = new Thread(new Runnable() {@Overridepublic void run() {try {int data = reader.read();while(data != -1) {System.out.println((char)data);data = reader.read();}reader.close();} catch (IOException e) {e.printStackTrace();}}});        thread3.start();        thread4.start();    }}

之所以叫管道,就是需要互联互通,我们通过例子代码中的构造方法(PipedReader reader = new PipedReader(writer))也可以看出来:

/**     * Creates a <code>PipedReader</code> so     * that it is connected to the piped writer     * <code>src</code>. Data written to <code>src</code>      * will then be available as input from this stream.     *     * @param      src   the stream to connect to.     * @exception  IOException  if an I/O error occurs.     */    public PipedReader(PipedWriter src) throws IOException {this(src, DEFAULT_PIPE_SIZE);    }

当新建一个PipedReader对象的同时,会用到一个已经创建好的PipedWriter对象,它的目的是为了给PipedWriter类中的PipedReader sink变量赋值:

package java.io;/** * Piped character-output streams. * * @version %I%, %E% * @authorMark Reinhold * @sinceJDK1.1 */public class PipedWriter extends Writer {    /* REMIND: identification of the read and write sides needs to be       more sophisticated.  Either using thread groups (but what about       pipes within a thread?) or using finalization (but it may be a       long time until the next GC). */    private PipedReader sink;

那么它是怎样给PipedWriter类中的PipedReader变量sink赋值呢,我们往下看:


/**     * Creates a <code>PipedReader</code> so that it is connected     * to the piped writer <code>src</code> and uses the specified     * pipe size for the pipe's buffer. Data written to <code>src</code>      * will then be  available as input from this stream.      * @param      src       the stream to connect to.     * @param      pipeSize  the size of the pipe's buffer.     * @exception  IOException  if an I/O error occurs.     * @exception  IllegalArgumentException if <code>pipeSize <= 0</code>.     * @since   1.6     */    public PipedReader(PipedWriter 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 char[pipeSize];    }

这里我们可以看到变量全局变量protected byte buffer[];这个数组就是用来存放我们需要读取流中的数据,等会我们会来介绍这个流中的数据是什么时候给赋值的。


/**     * Causes this piped reader to be connected     * to the piped  writer <code>src</code>.     * If this object is already connected to some     * other piped writer, an <code>IOException</code>     * is thrown.     * <p>     * If <code>src</code> is an     * unconnected piped writer and <code>snk</code>     * is an unconnected piped reader, they     * may be connected by either the call:     * <p>     * <pre><code>snk.connect(src)</code> </pre>      * <p>     * or the call:     * <p>     * <pre><code>src.connect(snk)</code> </pre>      * <p>     * The two     * calls have the same effect.     *     * @param      src   The piped writer to connect to.     * @exception  IOException  if an I/O error occurs.     */    public void connect(PipedWriter src) throws IOException {src.connect(this);    }

/**     * Connects this piped writer to a receiver. If this object     * is already connected to some other piped reader, an      * <code>IOException</code> is thrown.     * <p>     * If <code>snk</code> is an unconnected piped reader and      * <code>src</code> is an unconnected piped writer, they may      * be connected by either the call:     * <blockquote><pre>     * src.connect(snk)</pre></blockquote>     * or the call:     * <blockquote><pre>     * snk.connect(src)</pre></blockquote>     * The two calls have the same effect.     *     * @param      snk   the piped reader to connect to.     * @exception  IOException  if an I/O error occurs.     */    public synchronized void connect(PipedReader snk) throws IOException {        if (snk == null) {            throw new NullPointerException();        } else if (sink != null || snk.connected) {    throw new IOException("Already connected");} else if (snk.closedByReader || closed) {            throw new IOException("Pipe closed");        }        sink = snk;snk.in = -1;snk.out = 0;        snk.connected = true;    }

到这里我们可以看到当final PipedReader reader = new PipedReader(writer);构造一个PipedReader对象的时候,它做到了两点:

•初始化PipedReader中的数组变量buffer[];

•将PipedReader对象赋值给PipedWriter类中的PipedReader变量sink

我们需要注意的是connect(PipedReader snk)方法加了一个synchronized变量,那么这个变量的意思是什么呢?


我们再来看下writer.write("Hello piped!");源码都做了些什么:

/**     * Writes a string.     *     * @param  str     *         String to be written     *     * @throws  IOException     *          If an I/O error occurs     */    public void write(String str) throws IOException {write(str, 0, str.length());    }

/**     * Writes <code>len</code> characters from the specified character array      * starting at offset <code>off</code> to this piped output stream.      * This method blocks until all the characters are written to the output     * stream.     * If a thread was reading data characters from the connected piped input      * stream, but the thread is no longer alive, then an      * <code>IOException</code> is thrown.     *     * @param      cbuf  the data.     * @param      off   the start offset in the data.     * @param      len   the number of characters to write.     * @exception  IOException  if the pipe is      *<a href=PipedOutputStream.html#BROKEN> <code>broken</code></a>,     *{@link #connect(java.io.PipedReader) unconnected}, closed     *or an I/O error occurs.     */    public void write(char cbuf[], int off, int len) throws IOException {        if (sink == null) {            throw new IOException("Pipe not connected");        } else if ((off | len | (off + len) | (cbuf.length - (off + len))) < 0) {    throw new IndexOutOfBoundsException();}sink.receive(cbuf, off, len);    }

这里我们要好好看下sink.receive(cbuf, off, len);方法。当我们写数据的同时,其实就把数据写入到了PipedReader数组buffer[]中了:

/**     * Receives data into an array of characters.  This method will     * block until some input is available.      */    synchronized void receive(char c[], int off, int len)  throws IOException {while (--len >= 0) {    receive(c[off++]);}    }

/**     * Receives a char of data. This method will block if no input is     * available.     */    synchronized void receive(int c) throws IOException {        if (!connected) {            throw new IOException("Pipe not connected");        } else if (closedByWriter || closedByReader) {    throw new IOException("Pipe closed");} else if (readSide != null && !readSide.isAlive()) {            throw new IOException("Read end dead");        }writeSide = Thread.currentThread();while (in == out) {    if ((readSide != null) && !readSide.isAlive()) {throw new IOException("Pipe broken");    }    /* full: kick any waiting readers */    notifyAll();    try {        wait(1000);    } catch (InterruptedException ex) {throw new java.io.InterruptedIOException();    }}if (in < 0) {    in = 0;    out = 0;}buffer[in++] = (char) c;if (in >= buffer.length) {    in = 0;}    }


0 0