Java-IO之PipedReader和PipedWriter

本文介绍Java IO中的PipedReader和PipedWriter,它们用于实现线程间的数据通讯。通过示例代码展示了如何使用这两种类进行数据传递。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java-IO之PipedReader和PipedWriter

标签: Java IOPipedReaderPipedWriter
  889人阅读  评论(0)  收藏  举报
  分类:

PipedReader和PipedWriter与PipedInputStream和PipedOutputStream一样,都可以用于管道通信。PipedWriter是字符管道输出流,继承于Writer;PipedReader是字符管道输入流,继承于Reader,PipedWriter和PipedReader的作用是可以通过管道进行线程间的通讯。两者必须要配套使用。

示例程序:

[java]  view plain  copy
 print ?
  1. public class Receiver extends Thread {  
  2.   
  3.     // 管道输入流对象。  
  4.     // 它和“管道输出流(PipedWriter)”对象绑定,  
  5.     // 从而可以接收“管道输出流”的数据,再让用户读取。  
  6.     private PipedReader in = new PipedReader();  
  7.   
  8.     // 获得“管道输入流对象”  
  9.     public PipedReader getReader()  
  10.     {  
  11.         return in;  
  12.     }  
  13.   
  14.     @Override  
  15.     public void run(){  
  16.         readMessageOnce() ;  
  17.         //readMessageContinued() ;  
  18.     }  
  19.   
  20.     // 从“管道输入流”中读取1次数据  
  21.     public void readMessageOnce(){  
  22.         // 虽然buf的大小是2048个字符,但最多只会从“管道输入流”中读取1024个字符。  
  23.         // 因为,“管道输入流”的缓冲区大小默认只有1024个字符。  
  24.         char[] buf = new char[2048];  
  25.         try {  
  26.             int len = in.read(buf);  
  27.             System.out.println(new String(buf,0,len));  
  28.             in.close();  
  29.         } catch (IOException e) {  
  30.             e.printStackTrace();  
  31.         }  
  32.     }  
  33.   
  34.     // 从“管道输入流”读取>1024个字符时,就停止读取  
  35.     public void readMessageContinued()  
  36.     {  
  37.         int total=0;  
  38.         while(true) {  
  39.             char[] buf = new char[1024];  
  40.             try {  
  41.                 int len = in.read(buf);  
  42.                 total += len;  
  43.                 System.out.println(new String(buf,0,len));  
  44.                 // 若读取的字符总数>1024,则退出循环。  
  45.                 if (total > 1024)  
  46.                         break;  
  47.                 } catch (IOException e) {  
  48.                     e.printStackTrace();  
  49.                 }  
  50.         }  
  51.   
  52.         try {  
  53.             in.close();  
  54.         } catch (IOException e) {  
  55.                 e.printStackTrace();  
  56.         }  
  57.     }  
  58. }  

[java]  view plain  copy
 print ?
  1. public class Sender extends Thread {  
  2.     // 管道输出流对象。  
  3.     // 它和“管道输入流(PipedReader)”对象绑定,  
  4.     // 从而可以将数据发送给“管道输入流”的数据,然后用户可以从“管道输入流”读取数据。  
  5.     private PipedWriter out = new PipedWriter();  
  6.     // 获得“管道输出流”对象  
  7.     public PipedWriter getWriter(){  
  8.         return out;  
  9.     }  
  10.   
  11.     @Override  
  12.     public void run(){  
  13.         writeShortMessage();  
  14.         //writeLongMessage();  
  15.     }  
  16.   
  17.     // 向“管道输出流”中写入一则较简短的消息:"this is a short message"   
  18.     private void writeShortMessage() {  
  19.         String strInfo = "this is a short message" ;  
  20.         try {  
  21.             out.write(strInfo.toCharArray());  
  22.             out.close();  
  23.         } catch (IOException e) {  
  24.             e.printStackTrace();  
  25.         }  
  26.     }  
  27.     // 向“管道输出流”中写入一则较长的消息  
  28.     private void writeLongMessage() {  
  29.         StringBuilder sb = new StringBuilder();  
  30.         // 通过for循环写入1020个字符  
  31.         for (int i=0; i<102; i++)  
  32.             sb.append("0123456789");  
  33.             // 再写入26个字符。  
  34.             sb.append("abcdefghijklmnopqrstuvwxyz");  
  35.             // str的总长度是1020+26=1046个字符  
  36.             String str = sb.toString();  
  37.         try {  
  38.             // 将1046个字符写入到“管道输出流”中  
  39.             out.write(str);  
  40.             out.close();  
  41.         } catch (IOException e) {  
  42.             e.printStackTrace();  
  43.         }  
  44.     }  
  45. }  

[java]  view plain  copy
 print ?
  1. public class PipeTest {  
  2.   
  3.     public static void main(String[] args) {     
  4.         Sender t1 = new Sender();     
  5.   
  6.         Receiver t2 = new Receiver();     
  7.   
  8.         PipedWriter out = t1.getWriter();     
  9.   
  10.         PipedReader in = t2.getReader();  
  11.         try {     
  12.             //管道连接。下面2句话的本质是一样。  
  13.             //out.connect(in);     
  14.             in.connect(out);     
  15.   
  16.             /**   
  17.             * Thread类的START方法:   
  18.             * 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。    
  19.             * 结果是两个线程并发地运行;当前线程(从调用返回给 start 方法)和另一个线程(执行其 run 方法)。    
  20.             * 多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。    
  21.             */  
  22.             t1.start();  
  23.             t2.start();  
  24.         } catch (IOException e) {  
  25.              e.printStackTrace();  
  26.         }  
  27.     }  
  28. }  

输出结果:
this is a short message

基于JDK8的PipedReader的源码:

[java]  view plain  copy
 print ?
  1. public class PipedReader extends Reader {  
  2.     boolean closedByWriter = false;  
  3.     boolean closedByReader = false;  
  4.     boolean connected = false;  
  5.   
  6.     /* REMIND: identification of the read and write sides needs to be 
  7.        more sophisticated.  Either using thread groups (but what about 
  8.        pipes within a thread?) or using finalization (but it may be a 
  9.        long time until the next GC). */  
  10.     Thread readSide;  
  11.     Thread writeSide;  
  12.   
  13.     /** 
  14.      * The size of the pipe's circular input buffer. 
  15.      */  
  16.     //默认的输入缓冲大小为1024  
  17.     private static final int DEFAULT_PIPE_SIZE = 1024;  
  18.   
  19.     /** 
  20.      * The circular buffer into which incoming data is placed. 
  21.      */  
  22.     //字符数组  
  23.     char buffer[];  
  24.   
  25.     /** 
  26.      * The index of the position in the circular buffer at which the 
  27.      * next character of data will be stored when received from the connected 
  28.      * piped writer. <code>in<0</code> implies the buffer is empty, 
  29.      * <code>in==out</code> implies the buffer is full 
  30.      */  
  31.     //输入标志位  
  32.     int in = -1;  
  33.   
  34.     /** 
  35.      * The index of the position in the circular buffer at which the next 
  36.      * character of data will be read by this piped reader. 
  37.      */  
  38.     //输出标志位,in==out表示为满  
  39.     int out = 0;  
  40.     //构造函数  
  41.     public PipedReader(PipedWriter src) throws IOException {  
  42.         this(src, DEFAULT_PIPE_SIZE);  
  43.     }  
  44.     //构造函数,有管道大小  
  45.     public PipedReader(PipedWriter src, int pipeSize) throws IOException {  
  46.         initPipe(pipeSize);  
  47.         connect(src);  
  48.     }  
  49.     //没有连接,必须链接才行  
  50.     public PipedReader() {  
  51.         initPipe(DEFAULT_PIPE_SIZE);  
  52.     }  
  53.     public PipedReader(int pipeSize) {  
  54.         initPipe(pipeSize);  
  55.     }  
  56.     //构建pipeSize大小的字符缓冲区  
  57.     private void initPipe(int pipeSize) {  
  58.         if (pipeSize <= 0) {  
  59.             throw new IllegalArgumentException("Pipe size <= 0");  
  60.         }  
  61.     buffer = new char[pipeSize];  
  62.     }  
  63.     //Reader与Writer连接  
  64.     public void connect(PipedWriter src) throws IOException {  
  65.         src.connect(this);  
  66.     }  
  67.   
  68.     /** 
  69.      * Receives a char of data. This method will block if no input is 
  70.      * available. 
  71.      */  
  72.     //接受数据,  
  73.     synchronized void receive(int c) throws IOException {  
  74.         if (!connected) {  
  75.                 throw new IOException("Pipe not connected");  
  76.         } else if (closedByWriter || closedByReader) {  
  77.                 throw new IOException("Pipe closed");  
  78.         } else if (readSide != null && !readSide.isAlive()) {  
  79.                 throw new IOException("Read end dead");  
  80.         }  
  81.   
  82.         writeSide = Thread.currentThread();  
  83.         while (in == out) {  
  84.             if ((readSide != null) && !readSide.isAlive()) {  
  85.                 throw new IOException("Pipe broken");  
  86.             }  
  87.         /* full: kick any waiting readers */  
  88.         notifyAll();  
  89.             try {  
  90.                 wait(1000);  
  91.             } catch (InterruptedException ex) {  
  92.                 throw new java.io.InterruptedIOException();  
  93.             }  
  94.         }  
  95.         if (in < 0) {  
  96.             in = 0;  
  97.             out = 0;  
  98.         }  
  99.         buffer[in++] = (char) c;  
  100.         if (in >= buffer.length) {  
  101.             in = 0;  
  102.         }  
  103.     }  
  104.   
  105.     /** 
  106.      * Receives data into an array of characters.  This method will 
  107.      * block until some input is available. 
  108.      */  
  109.     synchronized void receive(char c[], int off, int len)  throws IOException {  
  110.         while (--len >= 0) {  
  111.             receive(c[off++]);  
  112.         }  
  113.     }  
  114.   
  115.     /** 
  116.      * Notifies all waiting threads that the last character of data has been 
  117.      * received. 
  118.      */  
  119.     synchronized void receivedLast() {  
  120.         closedByWriter = true;  
  121.         notifyAll();  
  122.     }  
  123.   
  124.     /** 
  125.      * Reads the next character of data from this piped stream. 
  126.      * If no character is available because the end of the stream 
  127.      * has been reached, the value <code>-1</code> is returned. 
  128.      * This method blocks until input data is available, the end of 
  129.      * the stream is detected, or an exception is thrown. 
  130.      * 
  131.      * @return     the next character of data, or <code>-1</code> if the end of the 
  132.      *             stream is reached. 
  133.      * @exception  IOException  if the pipe is 
  134.      *          <a href=PipedInputStream.html#BROKEN> <code>broken</code></a>, 
  135.      *          {@link #connect(java.io.PipedWriter) unconnected}, closed, 
  136.      *          or an I/O error occurs. 
  137.      */  
  138.     public synchronized int read()  throws IOException {  
  139.         if (!connected) {  
  140.             throw new IOException("Pipe not connected");  
  141.         } else if (closedByReader) {  
  142.             throw new IOException("Pipe closed");  
  143.         } else if (writeSide != null && !writeSide.isAlive()  
  144.                 && !closedByWriter && (in < 0)) {  
  145.             throw new IOException("Write end dead");  
  146.         }  
  147.   
  148.         readSide = Thread.currentThread();  
  149.         int trials = 2;  
  150.         while (in < 0) {  
  151.             if (closedByWriter) {  
  152.                 /* closed by writer, return EOF */  
  153.                 return -1;  
  154.             }  
  155.             if ((writeSide != null) && (!writeSide.isAlive()) && (--trials < 0)) {  
  156.                 throw new IOException("Pipe broken");  
  157.             }  
  158.             /* might be a writer waiting */  
  159.             notifyAll();  
  160.             try {  
  161.                 wait(1000);  
  162.             } catch (InterruptedException ex) {  
  163.                 throw new java.io.InterruptedIOException();  
  164.             }  
  165.         }  
  166.         int ret = buffer[out++];  
  167.         if (out >= buffer.length) {  
  168.             out = 0;  
  169.         }  
  170.         if (in == out) {  
  171.             /* now empty */  
  172.             in = -1;  
  173.         }  
  174.         return ret;  
  175.     }  
  176.   
  177.     /** 
  178.      * Reads up to <code>len</code> characters of data from this piped 
  179.      * stream into an array of characters. Less than <code>len</code> characters 
  180.      * will be read if the end of the data stream is reached or if 
  181.      * <code>len</code> exceeds the pipe's buffer size. This method 
  182.      * blocks until at least one character of input is available. 
  183.      * 
  184.      * @param      cbuf     the buffer into which the data is read. 
  185.      * @param      off   the start offset of the data. 
  186.      * @param      len   the maximum number of characters read. 
  187.      * @return     the total number of characters read into the buffer, or 
  188.      *             <code>-1</code> if there is no more data because the end of 
  189.      *             the stream has been reached. 
  190.      * @exception  IOException  if the pipe is 
  191.      *                  <a href=PipedInputStream.html#BROKEN> <code>broken</code></a>, 
  192.      *                  {@link #connect(java.io.PipedWriter) unconnected}, closed, 
  193.      *                  or an I/O error occurs. 
  194.      */  
  195.     public synchronized int read(char cbuf[], int off, int len)  throws IOException {  
  196.         if (!connected) {  
  197.             throw new IOException("Pipe not connected");  
  198.         } else if (closedByReader) {  
  199.             throw new IOException("Pipe closed");  
  200.         } else if (writeSide != null && !writeSide.isAlive()  
  201.                 && !closedByWriter && (in < 0)) {  
  202.             throw new IOException("Write end dead");  
  203.         }  
  204.   
  205.         if ((off < 0) || (off > cbuf.length) || (len < 0) ||((off + len) > cbuf.length) || ((off + len) < 0)) {  
  206.             throw new IndexOutOfBoundsException();  
  207.         } else if (len == 0) {  
  208.             return 0;  
  209.         }  
  210.   
  211.         /* possibly wait on the first character */  
  212.         int c = read();  
  213.         if (c < 0) {  
  214.             return -1;  
  215.         }  
  216.         cbuf[off] =  (char)c;  
  217.         int rlen = 1;  
  218.         while ((in >= 0) && (--len > 0)) {  
  219.             cbuf[off + rlen] = buffer[out++];  
  220.             rlen++;  
  221.             if (out >= buffer.length) {  
  222.                 out = 0;  
  223.             }  
  224.             if (in == out) {  
  225.                 /* now empty */  
  226.                 in = -1;  
  227.             }  
  228.         }  
  229.         return rlen;  
  230.     }  
  231.   
  232.     /** 
  233.      * Tell whether this stream is ready to be read.  A piped character 
  234.      * stream is ready if the circular buffer is not empty. 
  235.      * 
  236.      * @exception  IOException  if the pipe is 
  237.      *                  <a href=PipedInputStream.html#BROKEN> <code>broken</code></a>, 
  238.      *                  {@link #connect(java.io.PipedWriter) unconnected}, or closed. 
  239.      */  
  240.     //是否准备好可以读  
  241.     public synchronized boolean ready() throws IOException {  
  242.         if (!connected) {  
  243.             throw new IOException("Pipe not connected");  
  244.         } else if (closedByReader) {  
  245.             throw new IOException("Pipe closed");  
  246.         } else if (writeSide != null && !writeSide.isAlive()&& !closedByWriter && (in < 0)) {  
  247.             throw new IOException("Write end dead");  
  248.         }  
  249.         if (in < 0) {  
  250.             return false;  
  251.         } else {  
  252.             return true;  
  253.         }  
  254.     }  
  255.   
  256.     /** 
  257.      * Closes this piped stream and releases any system resources 
  258.      * associated with the stream. 
  259.      * 
  260.      * @exception  IOException  if an I/O error occurs. 
  261.      */  
  262.     //关闭管道流,释放资源  
  263.     public void close()  throws IOException {  
  264.         in = -1;  
  265.         closedByReader = true;  
  266.     }  
  267. }  

基于JDK8的PipedWriter源码:

[java]  view plain  copy
 print ?
  1. public class PipedWriter extends Writer {  
  2.   
  3.         /* REMIND: identification of the read and write sides needs to be 
  4.        more sophisticated.  Either using thread groups (but what about 
  5.        pipes within a thread?) or using finalization (but it may be a 
  6.        long time until the next GC). */  
  7.         private PipedReader sink;  
  8.   
  9.     /* This flag records the open status of this particular writer. It 
  10.      * is independent of the status flags defined in PipedReader. It is 
  11.      * used to do a sanity check on connect. 
  12.      */  
  13.     private boolean closed = false;  
  14.   
  15.     /** 
  16.      * Creates a piped writer connected to the specified piped 
  17.      * reader. Data characters written to this stream will then be 
  18.      * available as input from <code>snk</code>. 
  19.      * 
  20.      * @param      snk   The piped reader to connect to. 
  21.      * @exception  IOException  if an I/O error occurs. 
  22.      */  
  23.     //构造函数,连接Reader  
  24.     public PipedWriter(PipedReader snk)  throws IOException {  
  25.         connect(snk);  
  26.     }  
  27.   
  28.     /** 
  29.      * Creates a piped writer that is not yet connected to a 
  30.      * piped reader. It must be connected to a piped reader, 
  31.      * either by the receiver or the sender, before being used. 
  32.      * 
  33.      * @see     java.io.PipedReader#connect(java.io.PipedWriter) 
  34.      * @see     java.io.PipedWriter#connect(java.io.PipedReader) 
  35.      */  
  36.     public PipedWriter() {  
  37.     }  
  38.     //连接Reader,初始化in和out  
  39.     public synchronized void connect(PipedReader snk) throws IOException {  
  40.         if (snk == null) {  
  41.             throw new NullPointerException();  
  42.         } else if (sink != null || snk.connected) {  
  43.             throw new IOException("Already connected");  
  44.         } else if (snk.closedByReader || closed) {  
  45.             throw new IOException("Pipe closed");  
  46.         }  
  47.   
  48.         sink = snk;  
  49.         snk.in = -1;  
  50.         snk.out = 0;  
  51.         snk.connected = true;  
  52.     }  
  53.     //写字符  
  54.     public void write(int c)  throws IOException {  
  55.         if (sink == null) {  
  56.             throw new IOException("Pipe not connected");  
  57.         }  
  58.         sink.receive(c);  
  59.     }  
  60.     public void write(char cbuf[], int off, int len) throws IOException {  
  61.         if (sink == null) {  
  62.             throw new IOException("Pipe not connected");  
  63.         } else if ((off | len | (off + len) | (cbuf.length - (off + len))) < 0) {  
  64.             throw new IndexOutOfBoundsException();  
  65.         }  
  66.         sink.receive(cbuf, off, len);  
  67.     }  
  68.   
  69.     /** 
  70.      * Flushes this output stream and forces any buffered output characters 
  71.      * to be written out. 
  72.      * This will notify any readers that characters are waiting in the pipe. 
  73.      * 
  74.      * @exception  IOException  if the pipe is closed, or an I/O error occurs. 
  75.      */  
  76.     //刷新,强制缓存写出  
  77.     public synchronized void flush() throws IOException {  
  78.         if (sink != null) {  
  79.             if (sink.closedByReader || closed) {  
  80.                     throw new IOException("Pipe closed");  
  81.             }  
  82.             synchronized (sink) {  
  83.                 sink.notifyAll();  
  84.             }  
  85.         }  
  86.     }  
  87.   
  88.     /** 
  89.      * Closes this piped output stream and releases any system resources 
  90.      * associated with this stream. This stream may no longer be used for 
  91.      * writing characters. 
  92.      * 
  93.      * @exception  IOException  if an I/O error occurs. 
  94.      */  
  95.     public void close()  throws IOException {  
  96.         closed = true;  
  97.         if (sink != null) {  
  98.             sink.receivedLast();  
  99.         }  
  100.     }  
  101. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值