Java-IO之PipedReader和PipedWriter
PipedReader和PipedWriter与PipedInputStream和PipedOutputStream一样,都可以用于管道通信。PipedWriter是字符管道输出流,继承于Writer;PipedReader是字符管道输入流,继承于Reader,PipedWriter和PipedReader的作用是可以通过管道进行线程间的通讯。两者必须要配套使用。
示例程序:
public class Receiver extends Thread {
// 管道输入流对象。
// 它和“管道输出流(PipedWriter)”对象绑定,
// 从而可以接收“管道输出流”的数据,再让用户读取。
private PipedReader in = new PipedReader();
// 获得“管道输入流对象”
public PipedReader getReader()
{
return in;
}
@Override
public void run(){
readMessageOnce() ;
//readMessageContinued() ;
}
// 从“管道输入流”中读取1次数据
public void readMessageOnce(){
// 虽然buf的大小是2048个字符,但最多只会从“管道输入流”中读取1024个字符。
// 因为,“管道输入流”的缓冲区大小默认只有1024个字符。
char[] buf = new char[2048];
try {
int len = in.read(buf);
System.out.println(new String(buf,0,len));
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// 从“管道输入流”读取>1024个字符时,就停止读取
public void readMessageContinued()
{
int total=0;
while(true) {
char[] buf = new char[1024];
try {
int len = in.read(buf);
total += len;
System.out.println(new String(buf,0,len));
// 若读取的字符总数>1024,则退出循环。
if (total > 1024)
break;
} catch (IOException e) {
e.printStackTrace();
}
}
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class Sender extends Thread {
// 管道输出流对象。
// 它和“管道输入流(PipedReader)”对象绑定,
// 从而可以将数据发送给“管道输入流”的数据,然后用户可以从“管道输入流”读取数据。
private PipedWriter out = new PipedWriter();
// 获得“管道输出流”对象
public PipedWriter getWriter(){
return out;
}
@Override
public void run(){
writeShortMessage();
//writeLongMessage();
}
// 向“管道输出流”中写入一则较简短的消息:"this is a short message"
private void writeShortMessage() {
String strInfo = "this is a short message" ;
try {
out.write(strInfo.toCharArray());
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// 向“管道输出流”中写入一则较长的消息
private void writeLongMessage() {
StringBuilder sb = new StringBuilder();
// 通过for循环写入1020个字符
for (int i=0; i<102; i++)
sb.append("0123456789");
// 再写入26个字符。
sb.append("abcdefghijklmnopqrstuvwxyz");
// str的总长度是1020+26=1046个字符
String str = sb.toString();
try {
// 将1046个字符写入到“管道输出流”中
out.write(str);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class PipeTest {
public static void main(String[] args) {
Sender t1 = new Sender();
Receiver t2 = new Receiver();
PipedWriter out = t1.getWriter();
PipedReader in = t2.getReader();
try {
//管道连接。下面2句话的本质是一样。
//out.connect(in);
in.connect(out);
/**
* Thread类的START方法:
* 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
* 结果是两个线程并发地运行;当前线程(从调用返回给 start 方法)和另一个线程(执行其 run 方法)。
* 多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。
*/
t1.start();
t2.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
基于JDK8的PipedReader的源码:
public class PipedReader extends Reader {
boolean closedByWriter = false;
boolean closedByReader = false;
boolean connected = false;
/* 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). */
Thread readSide;
Thread writeSide;
/**
* The size of the pipe's circular input buffer.
*/
//默认的输入缓冲大小为1024
private static final int DEFAULT_PIPE_SIZE = 1024;
/**
* The circular buffer into which incoming data is placed.
*/
//字符数组
char buffer[];
/**
* The index of the position in the circular buffer at which the
* next character of data will be stored when received from the connected
* piped writer. <code>in<0</code> implies the buffer is empty,
* <code>in==out</code> implies the buffer is full
*/
//输入标志位
int in = -1;
/**
* The index of the position in the circular buffer at which the next
* character of data will be read by this piped reader.
*/
//输出标志位,in==out表示为满
int out = 0;
//构造函数
public PipedReader(PipedWriter src) throws IOException {
this(src, DEFAULT_PIPE_SIZE);
}
//构造函数,有管道大小
public PipedReader(PipedWriter src, int pipeSize) throws IOException {
initPipe(pipeSize);
connect(src);
}
//没有连接,必须链接才行
public PipedReader() {
initPipe(DEFAULT_PIPE_SIZE);
}
public PipedReader(int pipeSize) {
initPipe(pipeSize);
}
//构建pipeSize大小的字符缓冲区
private void initPipe(int pipeSize) {
if (pipeSize <= 0) {
throw new IllegalArgumentException("Pipe size <= 0");
}
buffer = new char[pipeSize];
}
//Reader与Writer连接
public void connect(PipedWriter src) throws IOException {
src.connect(this);
}
/**
* 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;
}
}
/**
* 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++]);
}
}
/**
* Notifies all waiting threads that the last character of data has been
* received.
*/
synchronized void receivedLast() {
closedByWriter = true;
notifyAll();
}
/**
* Reads the next character of data from this piped stream.
* If no character is available because the end of the stream
* has been reached, the value <code>-1</code> is returned.
* This method blocks until input data is available, the end of
* the stream is detected, or an exception is thrown.
*
* @return the next character of data, or <code>-1</code> if the end of the
* stream is reached.
* @exception IOException if the pipe is
* <a href=PipedInputStream.html#BROKEN> <code>broken</code></a>,
* {@link #connect(java.io.PipedWriter) unconnected}, closed,
* or an I/O error occurs.
*/
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++];
if (out >= buffer.length) {
out = 0;
}
if (in == out) {
/* now empty */
in = -1;
}
return ret;
}
/**
* Reads up to <code>len</code> characters of data from this piped
* stream into an array of characters. Less than <code>len</code> characters
* will be read if the end of the data stream is reached or if
* <code>len</code> exceeds the pipe's buffer size. This method
* blocks until at least one character of input is available.
*
* @param cbuf the buffer into which the data is read.
* @param off the start offset of the data.
* @param len the maximum number of characters read.
* @return the total number of characters read into the buffer, or
* <code>-1</code> if there is no more data because the end of
* the stream has been reached.
* @exception IOException if the pipe is
* <a href=PipedInputStream.html#BROKEN> <code>broken</code></a>,
* {@link #connect(java.io.PipedWriter) unconnected}, closed,
* or an I/O error occurs.
*/
public synchronized int read(char cbuf[], int off, int len) 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");
}
if ((off < 0) || (off > cbuf.length) || (len < 0) ||((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
/* possibly wait on the first character */
int c = read();
if (c < 0) {
return -1;
}
cbuf[off] = (char)c;
int rlen = 1;
while ((in >= 0) && (--len > 0)) {
cbuf[off + rlen] = buffer[out++];
rlen++;
if (out >= buffer.length) {
out = 0;
}
if (in == out) {
/* now empty */
in = -1;
}
}
return rlen;
}
/**
* Tell whether this stream is ready to be read. A piped character
* stream is ready if the circular buffer is not empty.
*
* @exception IOException if the pipe is
* <a href=PipedInputStream.html#BROKEN> <code>broken</code></a>,
* {@link #connect(java.io.PipedWriter) unconnected}, or closed.
*/
//是否准备好可以读
public synchronized boolean ready() 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");
}
if (in < 0) {
return false;
} else {
return true;
}
}
/**
* Closes this piped stream and releases any system resources
* associated with the stream.
*
* @exception IOException if an I/O error occurs.
*/
//关闭管道流,释放资源
public void close() throws IOException {
in = -1;
closedByReader = true;
}
}
基于JDK8的PipedWriter源码:
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;
/* This flag records the open status of this particular writer. It
* is independent of the status flags defined in PipedReader. It is
* used to do a sanity check on connect.
*/
private boolean closed = false;
/**
* Creates a piped writer connected to the specified piped
* reader. Data characters written to this stream will then be
* available as input from <code>snk</code>.
*
* @param snk The piped reader to connect to.
* @exception IOException if an I/O error occurs.
*/
//构造函数,连接Reader
public PipedWriter(PipedReader snk) throws IOException {
connect(snk);
}
/**
* Creates a piped writer that is not yet connected to a
* piped reader. It must be connected to a piped reader,
* either by the receiver or the sender, before being used.
*
* @see java.io.PipedReader#connect(java.io.PipedWriter)
* @see java.io.PipedWriter#connect(java.io.PipedReader)
*/
public PipedWriter() {
}
//连接Reader,初始化in和out
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;
}
//写字符
public void write(int c) throws IOException {
if (sink == null) {
throw new IOException("Pipe not connected");
}
sink.receive(c);
}
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);
}
/**
* Flushes this output stream and forces any buffered output characters
* to be written out.
* This will notify any readers that characters are waiting in the pipe.
*
* @exception IOException if the pipe is closed, or an I/O error occurs.
*/
//刷新,强制缓存写出
public synchronized void flush() throws IOException {
if (sink != null) {
if (sink.closedByReader || closed) {
throw new IOException("Pipe closed");
}
synchronized (sink) {
sink.notifyAll();
}
}
}
/**
* Closes this piped output stream and releases any system resources
* associated with this stream. This stream may no longer be used for
* writing characters.
*
* @exception IOException if an I/O error occurs.
*/
public void close() throws IOException {
closed = true;
if (sink != null) {
sink.receivedLast();
}
}
}
Java-IO之PipedReader和PipedWriter的更多相关文章
- java io系列20之 PipedReader和PipedWriter
本章,我们学习PipedReader和PipedWriter.它们和“PipedInputStream和PipedOutputStream”一样,都可以用于管道通信. PipedWriter 是字符管 ...
- Java IO(十三)PipedReader 和 PipedWriter
Java IO(十三)PipedReader 和 PipedWriter 一.介绍 PipedReader 和 PipedWriter 分别是管道字符输入流和管道字符输出流,它们同 PipedInpu ...
- Java IO之字符流和文件
前面的博文介绍了字节流,那字符流又是什么流?从字面意思上看,字节流是面向字节的流,字符流是针对unicode编码的字符流,字符的单位一般比字节大,字节可以处理任何数据类型,通常在处理文本文件内容时,字 ...
- java IO流详解
流的概念和作用 学习Java IO,不得不提到的就是JavaIO流. 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...
- Java IO流学习总结
Java流操作有关的类或接口: Java流类图结构: 流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...
- [Java IO]03_字符流
Java程序中,一个字符等于两个字节. Reader 和 Writer 两个就是专门用于操作字符流的类. Writer Writer是一个字符流的抽象类. 它的定义如下: public abstra ...
- java io 流分类表
Java输入/输出流体系中常用的流分类(表内容来自java疯狂讲义) 注:下表中带下划线的是抽象类,不能创建对象.粗体部分是节点流,其他就是常用的处理流. 流分类 使用分类 字节输入流 字节输出流 字 ...
- java io 输入输出流
数据流分类: 流序列中的数据既可以是未经加工的原始二进制数据, 也可以是经一定编码处理后符合某种格式规定的特定数据. 因此Java中的流分为两种: 1) 字节流:数据流中最小的数据单元是字节 2) 字 ...
- Java IO流体系中常用的流分类
Java输入/输出流体系中常用的流分类(表内容来自java疯狂讲义) 注:下表中带下划线的是抽象类,不能创建对象.粗体部分是节点流,其他就是常用的处理流. 流分类 使用分类 字节输入流 字节输出流 字 ...
- java io系列01之 "目录"
java io 系列目录如下: 01. java io系列01之 "目录" 02. java io系列02之 ByteArrayInputStream的简介,源码分析和示例(包括 ...
随机推荐
- TensorFlow 中文资源全集,官方网站,安装教程,入门教程,实战项目,学习路径。
Awesome-TensorFlow-Chinese TensorFlow 中文资源全集,学习路径推荐: 官方网站,初步了解. 安装教程,安装之后跑起来. 入门教程,简单的模型学习和运行. 实战项目, ...
- JFinal 极速开发框架的优点和不足的地方
http://www.360doc.com/content/16/1226/10/31460730_617731802.shtml http://www.sohu.com/a/122571150_46 ...
- drool-6.5的自学demo
先丢代码地址 https://gitee.com/a247292980/drools 再丢pom.xml <project xmlns="http://maven.apache.org ...
- ubuntu + 不识别无线网卡简易处理方式 + 需有线联网
进入ubuntu, 连接有线网; 系统设置 -> 软件和更新 -> 附加驱动 -> 找到无线网卡驱动并更新 若无候选的无线网卡驱动,我就没招了.
- PHP使用prepare(),insert数据时要注意的一点!!!
今天看了PHP防SQL注入,使用预处理prepare,但是我insert数据时,总是插不进去,但是select却可以,弄了很久终于知道原来问题在这里,先上代码 <?php header('con ...
- c++ 深入理解数组
阅读前提:你得知道啥是数组. 本文需要弄清楚的问题如下: 1,数组作为函数参数,传入的是值,还是地址? 2,数组作为函数参数,数组的长度能否确定? 解决如下 1,数组作为函数参数,传入的是地址.因为数 ...
- 小程序上拉下拉共存时不可使用scroll-view的解决方法
使用 bindscrolltolower ,必须搭配使用的 scroll-view 会导致小程序 "enablePullDownRefresh": true 下拉不能使用. 解决方 ...
- leetcode刷题笔记326 3的幂
题目描述: 给出一个整数,写一个函数来确定这个数是不是3的一个幂. 后续挑战:你能不使用循环或者递归完成本题吗? 题目分析: 既然不使用循环或者递归,那我可要抖机灵了 如果某个数n为3的幂 ,则k=l ...
- JavaScript 代码规范
所有的 JavaScript 项目适用同一种规范. JavaScript 代码规范 代码规范通常包括以下几个方面: 变量和函数的命名规则 空格,缩进,注释的使用规则. 其他常用规范-- 规范的代码可以 ...
- Mac入门
Mac入门 桌面 windows桌面有图标罗列 Mac桌面有Dock 菜单栏 感觉上和Windows系统的底部菜单栏有点像,但是却略有不同,Mac的菜单栏默认在顶部 左侧的一些功能是固定不变的,跟随当 ...