管道的定义
在Linux中,管道是一种使用非常频繁的通信机制。从本质上说,管道也是一种文件,但它又和一般的文件有所不同,管道可以克服使用文件进行通信的两个问题,具体表现为:
- 限制管道的大小。实际上,管道是一个固定大小的缓冲区。在Linux中,该缓冲区的大小为1页,即4K字节,使得它的大小不像文件那样不加检验地增长。使用单个固定缓冲区也会带来问题,比如在写管道时可能变满,当这种情况发生时,随后对管道的write()调用将默认地被阻塞,等待某些数据被读取,以便腾出足够的空间供write()调用写。
- 读取进程也可能工作得比写进程快。当所有当前进程数据已被读取时,管道变空。当这种情况发生时,一个随后的read()调用将默认地被阻塞,等待某些数据被写入,这解决了read()调用返回文件结束的问题。
管道有如下特性:
- 管道可以把一个进程的标准输出流与另一个进程的标准输入流连接起来。
- 从管道读数据是一次性操作,数据一旦被读,它就从管道中被抛弃,释放空间以便写更多的数据。
- 管道只能半双工通信,即某一时刻只能单向传输。要实现父子进程双方互动通信,需要定义两个管道。
- 管道只能用于有亲缘关系进程间的通信。要实现独立进程间的通信可参照有名管道(FIFO)。
Linux/Windows的命令行中的管道
通过管道将命令执行的结果输出到文本:命令 > 文本(其中”>”为管道符号)。
例如,以下命令将当前目录下的文件信息输出到result.txt文本中。
Linux下,ls > result.txt
Windows下,dir > result.txt
Java中的管道
Java 提供管道功能,但只能用于线程间通讯。实现管道通信的类有两组:PipedInputStream 和 PipedOutputStream 或者是 PipedReader 和 PipedWriter。
PipedInputStream & PipedOutputStream
package com.demo.test;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class PipedDemo {
private static final int BUFF_SIZE = 255;
private static final int LOOP_COUNT = 10;
static class InputThread implements Runnable {
private PipedInputStream pis;
public InputThread(PipedInputStream pis) {
this.pis = pis;
}
@Override
public void run() {
byte[] buffer = new byte[BUFF_SIZE];
int len = -1;
do {
try {
len = pis.read(buffer);
System.out.println("len=" + len + ", buffer=" + new String(buffer));
} catch (IOException e) {
e.printStackTrace();
}
} while (len != -1);
try {
pis.close();
System.out.println("PipedIutputStream close");
} catch (IOException e) {
e.printStackTrace();
}
}
}
static class OutputThread implements Runnable {
private PipedOutputStream pos;
public OutputThread(PipedOutputStream pos) {
this.pos = pos;
}
@Override
public void run() {
Date date = new Date();
for (int i = 0; i < LOOP_COUNT; i++) {
try {
String str = "(" + i + ")" + date.toString();
pos.write(str.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
pos.close();
System.out.println("PipedOutputStream close");
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static void testPipedStream() {
PipedInputStream pis = new PipedInputStream();
PipedOutputStream pos = new PipedOutputStream();
try {
// 连接“输入”、“输出”流,下面2个方法任选
pis.connect(pos);
// pos.connect(pis);
} catch (IOException e) {
e.printStackTrace();
}
int nThreads = 2;
ExecutorService executorService = Executors.newFixedThreadPool(nThreads);
executorService.execute(new InputThread(pis));
executorService.execute(new OutputThread(pos));
}
public static void main(String[] args) {
testPipedStream();
}
}
输出
PipedOutputStream close
len=255, buffer=(0)Fri Dec 02 10:58:27 CST 2016(1)Fri Dec 02 10:58:27 CST 2016(2)Fri Dec 02 10:58:27 CST 2016(3)Fri Dec 02 10:58:27 CST 2016(4)Fri Dec 02 10:58:27 CST 2016(5)Fri Dec 02 10:58:27 CST 2016(6)Fri Dec 02 10:58:27 CST 2016(7)Fri Dec 02 10:58:27 CST 2016(8)Fri
len=55, buffer=Dec 02 10:58:27 CST 2016(9)Fri Dec 02 10:58:27 CST 2016ST 2016(2)Fri Dec 02 10:58:27 CST 2016(3)Fri Dec 02 10:58:27 CST 2016(4)Fri Dec 02 10:58:27 CST 2016(5)Fri Dec 02 10:58:27 CST 2016(6)Fri Dec 02 10:58:27 CST 2016(7)Fri Dec 02 10:58:27 CST 2016(8)Fri
len=-1, buffer=Dec 02 10:58:27 CST 2016(9)Fri Dec 02 10:58:27 CST 2016ST 2016(2)Fri Dec 02 10:58:27 CST 2016(3)Fri Dec 02 10:58:27 CST 2016(4)Fri Dec 02 10:58:27 CST 2016(5)Fri Dec 02 10:58:27 CST 2016(6)Fri Dec 02 10:58:27 CST 2016(7)Fri Dec 02 10:58:27 CST 2016(8)Fri
PipedIutputStream close
PipedReader & PipedWriter
package com.demo.test;
import java.io.IOException;
import java.io.PipedReader;
import java.io.PipedWriter;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class PipedDemo {
private static final int BUFF_SIZE = 255;
private static final int LOOP_COUNT = 10;
static class ReaderThread implements Runnable {
private PipedReader pr;
public ReaderThread(PipedReader pr) {
this.pr = pr;
}
@Override
public void run() {
char[] buffer = new char[BUFF_SIZE];
int len = -1;
do {
try {
len = pr.read(buffer);
System.out.println("len=" + len + ", buffer=" + new String(buffer));
} catch (IOException e) {
e.printStackTrace();
}
} while (len != -1);
try {
pr.close();
System.out.println("PipedReader close");
} catch (IOException e) {
e.printStackTrace();
}
}
}
static class WriterThread implements Runnable {
private PipedWriter pw;
public WriterThread(PipedWriter pw) {
this.pw = pw;
}
@Override
public void run() {
Date date = new Date();
for (int i = 0; i < LOOP_COUNT; i++) {
try {
String str = "(" + i + ")" + date.toString();
pw.write(str);
} catch (IOException e) {
e.printStackTrace();
}
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
pw.close();
System.out.println("PipedWriter close");
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static void testPipedWrapper() {
// 同样是两种初始化连接方式
// PipedReader pr = new PipedReader();
// try {
// PipedWriter pw = new PipedWriter(pr);
// } catch (IOException e) {
// e.printStackTrace();
// }
PipedWriter pw = new PipedWriter();
try {
PipedReader pr = new PipedReader(pw);
int nThreads = 2;
ExecutorService executorService = Executors.newFixedThreadPool(nThreads);
executorService.execute(new ReaderThread(pr));
executorService.execute(new WriterThread(pw));
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
testPipedStream();
try {
Thread.sleep(3000);
System.out.println();
} catch (InterruptedException e) {
e.printStackTrace();
}
testPipedWrapper();
}
}
输出
PipedWriter close
len=255, buffer=(0)Fri Dec 02 10:58:30 CST 2016(1)Fri Dec 02 10:58:30 CST 2016(2)Fri Dec 02 10:58:30 CST 2016(3)Fri Dec 02 10:58:30 CST 2016(4)Fri Dec 02 10:58:30 CST 2016(5)Fri Dec 02 10:58:30 CST 2016(6)Fri Dec 02 10:58:30 CST 2016(7)Fri Dec 02 10:58:30 CST 2016(8)Fri
len=55, buffer=Dec 02 10:58:30 CST 2016(9)Fri Dec 02 10:58:30 CST 2016ST 2016(2)Fri Dec 02 10:58:30 CST 2016(3)Fri Dec 02 10:58:30 CST 2016(4)Fri Dec 02 10:58:30 CST 2016(5)Fri Dec 02 10:58:30 CST 2016(6)Fri Dec 02 10:58:30 CST 2016(7)Fri Dec 02 10:58:30 CST 2016(8)Fri
len=-1, buffer=Dec 02 10:58:30 CST 2016(9)Fri Dec 02 10:58:30 CST 2016ST 2016(2)Fri Dec 02 10:58:30 CST 2016(3)Fri Dec 02 10:58:30 CST 2016(4)Fri Dec 02 10:58:30 CST 2016(5)Fri Dec 02 10:58:30 CST 2016(6)Fri Dec 02 10:58:30 CST 2016(7)Fri Dec 02 10:58:30 CST 2016(8)Fri
PipedReader close