Java:合并输入流
我的目标是创建(或使用现有的)InputStream实现(例如,MergeInputStream),该实现将尝试从多个InputStreams中读取并返回第一个结果。之后,它将释放锁并停止读取所有InputStreams,直到下一个mergeInputStream.read()调用。我很惊讶没有找到这样的工具。问题是:所有的源输入流都不是非常有限的(例如,不是一个文件,而是一个System.in、socket等),所以我不能使用SequenceInputReader。我知道这可能需要一些多线程机制,但我完全不知道如何做到这一点。我尝试用谷歌搜索,但没有结果。从多个来源读取输入并将其序列化为一个流的问题最好通过使用和解决。然而,这要求所有源都能够提供一个可选通道。情况可能是这样,也可能不是这样 如果可选通道不可用,您可以通过让读取实现执行以下操作来选择用单个线程解决它:对于每个输入流Java:合并输入流,java,multithreading,merge,inputstream,Java,Multithreading,Merge,Inputstream,我的目标是创建(或使用现有的)InputStream实现(例如,MergeInputStream),该实现将尝试从多个InputStreams中读取并返回第一个结果。之后,它将释放锁并停止读取所有InputStreams,直到下一个mergeInputStream.read()调用。我很惊讶没有找到这样的工具。问题是:所有的源输入流都不是非常有限的(例如,不是一个文件,而是一个System.in、socket等),所以我不能使用SequenceInputReader。我知道这可能需要一些多线程机
is
,检查is.available()>0
,如果是,则返回is.read()
。重复此过程,直到某些输入流具有可用数据
然而,这种方法有两个主要缺点:
InputStream
实现available()
,当且仅当read()
将阻塞时,它才会返回0。结果自然是,数据可能不会从这个流中读取,即使is.read()
将返回一个值。这是否会被视为一个bug是值得怀疑的,因为文档仅仅说明它应该返回可用字节数的“估计值”import java.io.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
public class MergedInputStream extends InputStream {
AtomicInteger openStreamCount;
BlockingQueue<Integer> buf = new ArrayBlockingQueue<Integer>(1);
InputStream[] sources;
public MergedInputStream(InputStream... sources) {
this.sources = sources;
openStreamCount = new AtomicInteger(sources.length);
for (int i = 0; i < sources.length; i++)
new ReadThread(i).start();
}
public void close() throws IOException {
String ex = "";
for (InputStream is : sources) {
try {
is.close();
} catch (IOException e) {
ex += e.getMessage() + " ";
}
}
if (ex.length() > 0)
throw new IOException(ex.substring(0, ex.length() - 1));
}
public int read() throws IOException {
if (openStreamCount.get() == 0)
return -1;
try {
return buf.take();
} catch (InterruptedException e) {
throw new IOException(e);
}
}
private class ReadThread extends Thread {
private final int src;
public ReadThread(int src) {
this.src = src;
}
public void run() {
try {
int data;
while ((data = sources[src].read()) != -1)
buf.put(data);
} catch (IOException ioex) {
} catch (InterruptedException e) {
}
openStreamCount.decrementAndGet();
}
}
}
import java.io.*;
导入java.util.concurrent.*;
导入java.util.concurrent.AtomicInteger;
公共类MergedInputStream扩展了InputStream{
原子整数openStreamCount;
BlockingQueue buf=新阵列BlockingQueue(1);
输入流[]源;
公共MergedInputStream(InputStream…源){
这个。来源=来源;
openStreamCount=新的AtomicInteger(sources.length);
for(int i=0;i0)
抛出新IOException(例如子字符串(0,例如length()-1));
}
public int read()引发IOException{
if(openStreamCount.get()==0)
返回-1;
试一试{
返回buf.take();
}捕捉(中断异常e){
抛出新的IOException(e);
}
}
私有类ReadThread扩展线程{
私人终审法院;
公共读取线程(int-src){
this.src=src;
}
公开募捐{
试一试{
int数据;
而((数据=源[src].read())!=-1)
buf.put(数据);
}捕获(IOException ioex){
}捕捉(中断异常e){
}
openStreamCount.decrementAndGet();
}
}
}
我可以想出三种方法:
- 使用非阻塞I/O()。这是最干净的解决方案
- 多个线程,每个合并的输入流一个线程。线程将阻塞相关输入流的
方法,然后在数据可用时通知read()
对象。MergeInputStream
中的MergedInputStream
方法将等待此通知,然后从相应的流中读取数据read()
- 具有繁忙循环的单线程。您的
方法需要循环检查每个合并输入流的MergeInputStream.read()
方法。如果没有可用数据,则睡眠几毫秒。重复此操作,直到其中一个合并输入流中的数据可用为止available()
available()
不保证返回可以在不阻塞的情况下读取的字节总数,但如果有任何可用数据(即调用read()
将不会阻塞),则应返回非零。如果有数据可用,许多InputStream
实现将返回1
,否则返回0
。单线程方案工作正常。我将学习NIO,并在未来的任务中尝试实现它。“谢谢你们两个。”冰冻蜘蛛。。。当然,在某些情况下它会很好地工作。在其他情况下,它将惨败。例如,见。我想说的是,没有任何保证,无论什么时候,只要你的程序I/O操作看起来有问题,你就必须怀疑并调查错误是否存在于这段代码中。所以,我别无选择,只能重写整个模块。。。谢谢你的链接。你链接到的论坛中的评论