有没有人有任何关于在Java中创建Pipe对象的建议, 既是InputStream又是OutputStream,因为Java没有多重继承,而且这两个流都是抽象类而不是接口?
潜在的需求是让一个对象可以传递给需要InputStream或OutputStream的东西来管道从一个线程输出到另一个线程的输入。
答案 0 :(得分:8)
似乎错过了这个问题的重点。如果我理解正确的话,你需要一个在一个线程中像InputStream一样工作的对象,在另一个线程中想要一个OutputStream来创建一个在两个线程之间进行通信的方法。
也许一个答案是使用组合而不是继承(无论如何都是推荐的练习)。使用getInputStream()和getOutputStream()方法创建一个包含彼此连接的PipedInputStream和PipedOutputStream的管道。
你不能直接将Pipe对象传递给需要流的东西,但是你可以传递它的get方法的返回值。
这对你有用吗?
答案 1 :(得分:5)
java.io.PipedOutputStream和java.io.PipedInputStream看起来是用于此场景的类。它们被设计为一起用于在线程之间管道数据。
如果你真的想要一些单个对象传递它,则需要包含其中一个并通过getter公开它们。
答案 2 :(得分:3)
我认为这是很常见的事情。看到这个问题。
Easy way to write contents of a Java InputStream to an OutputStream
答案 3 :(得分:1)
你不能创建一个从InputStream
和OutputStream
派生的类,因为它们不是接口,它们有通用的方法,而Java不允许多重继承(编译器没有如果您在新对象上调用InputStream.close()
,请知道是否致电OutputStream.close()
或close()
。
另一个问题是缓冲区。 Java希望为数据分配一个静态缓冲区(不会改变)。这意味着当你使用`java.io.PipedXxxStream'时,除非你使用两个不同的线程,否则写入数据最终会被阻塞。
所以Apocalisp的答案是正确的:你必须写一个复制循环。
我建议您在项目中包含Apache的commons-io,其中包含许多帮助例程,仅用于此类任务(在流,文件,字符串及其所有组合之间复制数据)。
答案 4 :(得分:1)
答案 5 :(得分:0)
我必须实现一个缓慢连接到Servlet的过滤器,所以基本上我将servlet输出流包装到QueueOutputStream中,它将每个字节(在小缓冲区中)添加到队列中,然后将这些小缓冲区输出到第二个输出流,所以在某种程度上它充当输入/输出流,恕我直言这比JDK管道更好,这不会很好地扩展,基本上在标准JDK实现中有太多的上下文切换(每次读/写),阻塞队列对于单个生产者/消费者场景来说是完美的:
import java.io.IOException;
import java.io.OutputStream;
import java.util.concurrent.*;
public class QueueOutputStream extends OutputStream
{
private static final int DEFAULT_BUFFER_SIZE=1024;
private static final byte[] END_SIGNAL=new byte[]{};
private final BlockingQueue<byte[]> queue=new LinkedBlockingDeque<>();
private final byte[] buffer;
private boolean closed=false;
private int count=0;
public QueueOutputStream()
{
this(DEFAULT_BUFFER_SIZE);
}
public QueueOutputStream(final int bufferSize)
{
if(bufferSize<=0){
throw new IllegalArgumentException("Buffer size <= 0");
}
this.buffer=new byte[bufferSize];
}
private synchronized void flushBuffer()
{
if(count>0){
final byte[] copy=new byte[count];
System.arraycopy(buffer,0,copy,0,count);
queue.offer(copy);
count=0;
}
}
@Override
public synchronized void write(final int b) throws IOException
{
if(closed){
throw new IllegalStateException("Stream is closed");
}
if(count>=buffer.length){
flushBuffer();
}
buffer[count++]=(byte)b;
}
@Override
public synchronized void write(final byte[] b, final int off, final int len) throws IOException
{
super.write(b,off,len);
}
@Override
public synchronized void close() throws IOException
{
flushBuffer();
queue.offer(END_SIGNAL);
closed=true;
}
public Future<Void> asyncSendToOutputStream(final ExecutorService executor, final OutputStream outputStream)
{
return executor.submit(
new Callable<Void>()
{
@Override
public Void call() throws Exception
{
try{
byte[] buffer=queue.take();
while(buffer!=END_SIGNAL){
outputStream.write(buffer);
buffer=queue.take();
}
outputStream.flush();
} catch(Exception e){
close();
throw e;
} finally{
outputStream.close();
}
return null;
}
}
);
}
答案 6 :(得分:0)
最好使用Pipe或ArrayBlockingQueue,我建议您不要使用PipedInput / OutputStream,因为它们有不好的作法,即使您在下面的链接中也看到它们已被要求弃用,因为它会引起很多问题。
https://bugs.openjdk.java.net/browse/JDK-8223048
对于BlockingQueue和Pipe,这里是一个简单的示例
管道:
Pipe pipe = Pipe.open();
Pipe.SinkChannel sinkChannel = pipe.sink();
String newData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();
while(buf.hasRemaining()) {
sinkChannel.write(buf);
}
Pipe.SourceChannel sourceChannel = pipe.source();
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);
参考:http://tutorials.jenkov.com/java-nio/pipe.html
BlockingQueue:
//Shared class used by threads
public class Buffer {
// ArrayBlockingQueue
private BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<Integer>(1);
public void get() {
// retrieve from ArrayBlockingQueue
try {
System.out.println("Consumer received - " + blockingQueue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void put(int data) {
try {
// putting in ArrayBlockingQueue
blockingQueue.put(data);
System.out.println("Producer produced - " + data);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
// Starting two threads
ExecutorService executorService = null;
try {
Buffer buffer = new Buffer();
executorService = Executors.newFixedThreadPool(2);
executorService.execute(new Producer(buffer));
executorService.execute(new Consumer(buffer));
} catch (Exception e) {
e.printStackTrace();
}finally {
if(executorService != null) {
executorService.shutdown();
}
}
}
public class Consumer implements Runnable {
private Buffer buffer;
public Consumer(Buffer buffer) {
this.buffer = buffer;
}
@Override
public void run() {
while (true) {
try {
buffer.get();
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Producer implements Runnable {
private Buffer buffer;
public Producer(Buffer buffer) {
this.buffer = buffer;
}
@Override
public void run() {
while (true) {
Random random = new Random();
int data = random.nextInt(1000);
buffer.put(data);
}
}
}
参考: https://github.com/kishanjavatrainer/ArrayBlockingQueueDemo/tree/master/ArrayBlockingQueueDemo