[重学Java基础][JavaIO流][Part.5]管道字符输入输出流
PipedReader
概述
PipedReader管道输入流 需要配合管道输出流PipedWriter使用 用于线程间通讯
在线程间开启一个管道 互相传输数据
源码分析
成员变量
PipedWriter对象是否关闭
boolean closedByWriter = false;
PipedReader对象是否关闭
boolean closedByReader = false;
连接是否关闭
boolean connected = false;
进行读入的线程
Thread readSide;
进行写出的线程
Thread writeSide;
默认的缓冲字符数组大小
private static final int DEFAULT_PIPE_SIZE = 1024;
缓冲字符数组
char buffer[];
下一个从管道读入到缓冲数组的字符游标位置 如果in==out说明已经读入完毕
int in = -1;
int out = 0;
成员方法
构造函数 可以自主制定管道缓冲大小或者使用默认值 指定与PipedReader相连的PipedWriter 对象
public PipedReader() {
initPipe(DEFAULT_PIPE_SIZE);
}
public PipedReader(int pipeSize) {
initPipe(pipeSize);
}
public PipedReader(PipedWriter src) throws IOException {
this(src, DEFAULT_PIPE_SIZE);
}
public PipedReader(PipedWriter src, int pipeSize) throws IOException {
initPipe(pipeSize);
connect(src);
}
连接 实际上调用的是PipedWriter 对象的connect()方法
public void connect(PipedWriter src) throws IOException {
src.connect(this);
}
接收方法
接收字符数据 只会在PipedWriter的write(int b)中会被调用
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();
每隔1s检查“管道状态”,并唤醒管道操作
若有“读取管道数据线程被阻塞”,则唤醒该线程
直到数据被全部读取(in==out)
while (in == out) {
if ((readSide != null) && !readSide.isAlive()) {
throw new IOException("Pipe broken");
}
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;
}
}
按字符读入 并制定起始位置和读入长度
synchronized void receive(char c[], int off, int len) throws IOException {
while (--len >= 0) {
receive(c[off++]);
}
}
接受完毕 通知所有线程此管道被关闭
synchronized void receivedLast() {
closedByWriter = true;
notifyAll();
}
读取方法和其他字符输入流读取类似 内容省略
PipedWriter
概述
源码分析
成员变量
PipedReader对象用于和PipedWriter通信
private PipedReader sink;
PipedWriter的关闭标记
private boolean closed = false;
成员方法
构造方法 可以指定连接的PipedReader 对象或者稍后指定
public PipedWriter(PipedReader snk) throws IOException {
connect(snk);
}
public PipedWriter() {
}
连接方法 将此字符输出管道连接到输入管道上
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;
设置Reader对象的连接状态为成功
snk.connected = true;
}
刷新管道方法 调用了PipedReader sink的notifyAll()方法 使当前的PipedReader 放弃对资源的占用 唤醒其他被阻塞的PipedReader 读取PipedWriter的值
public synchronized void flush() throws IOException {
if (sink != null) {
if (sink.closedByReader || closed) {
throw new IOException("Pipe closed");
}
synchronized (sink) {
sink.notifyAll();
}
}
}
写入方法 实际上是调用了PipedReader sink的接收方法
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);
}
PipedReader PipedWriter综合代码示例
发送端
class Sender extends Thread {
//发送端端设置一个内部类PipedWriter的实例对象out用于发送管道数据
private PipedWriter out = new PipedWriter();
// 获得“管道输出流”对象
public PipedWriter getWriter(){
return out;
}
@Override
public void run(){
writeShortMessage();
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Sender Over");
}
// 向“管道输出流”中写入数据
private void writeShortMessage() {
String strInfo = "this is message sender" ;
try {
out.write(strInfo.toCharArray());
} catch (IOException e) {
e.printStackTrace();
}
}
}
接收端
class Receiver extends Thread {
//接收端设置一个内部类PipedReader的实例对象in用于接受管道数据
private PipedReader in = new PipedReader();
//获取这个PipedReader对象 用于从外部设置接收端和发送端的连接
public PipedReader getReader(){
return in;
}
@Override
public void run(){
readMessage() ;
//必须全部读取完毕才能关闭连接 否则会报错
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Receiver Over");
}
// 从“管道输入流”中读取1次数据 需要自己截断 因为写入端是连续写入的
public void readMessage(){
char[] buf = new char[23];
try {
in.read(buf);
System.out.println(new String(buf,0,23));
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行主函数
public static void main(String[] args) throws IOException {
Sender sender=new Sender();
Receiver receiver=new Receiver();
sender.getWriter().connect(receiver.getReader());
sender.start();
receiver.start();
}
运行结果
this is message sender
Sender Over
Receiver Over