我搜索过高低,但无法找到关于NIO问题的最新,最新答案。
有没有办法从InputStream
转换为Channel
我可以使用Selector
?似乎Channels.newChannel()
是进行转换的唯一方法,但不提供AbstractSelectableChannel
的实例,这正是我所需要的。
更具体地说,我想从子进程的stdout
和stderr
流中读取,而不是为每个流创建一个线程,而且似乎这是在纯Java中实现它的唯一方法。由于这些流使用管道来回传递I / O,我很惊讶.newChannel
不会返回Pipe.SourceChannel
,这是AbstractSelectableChannel
的子类。
我正在使用Java 7(虽然如果8中有新功能,我仍然会很乐意回答)。
编辑:我也尝试将.newChannel()
的结果投射到可选择的频道无效 - 它不是可选择的频道。
答案 0 :(得分:3)
没有办法做你所要求的,但你不需要每个流一个线程。只需将流与为此目的提供的API合并,并读取当前线程中的输出。
答案 1 :(得分:0)
我遇到了同样的问题,但我可以将子进程的输出重定向到文件并稍后分析输出。您可以使用类似下面的代码,但它有一些缺点,应该添加一些代码。可以使用一些并发集合而不是锁。
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class InputPrcocessSelector {
final private Collection<Process> registeredProcesses = new HashSet<>();
final private Lock registeredProcessesLock = new ReentrantLock();
final private LinkedBlockingQueue<Process> readyProcesses = new LinkedBlockingQueue<>();
final private ExecutorService executorService = Executors.newSingleThreadExecutor();
final private static TimeUnit DEFAULT_TIME_UNIT = TimeUnit.MILLISECONDS;
final private static int DEFAULT_TIMEOUT = 100;
final private int timeOut;
final private TimeUnit timeUnit;
public InputPrcocessSelector() {
this(DEFAULT_TIMEOUT, DEFAULT_TIME_UNIT);
}
public InputPrcocessSelector(int timeOut, TimeUnit timeUnit) {
this.timeOut = timeOut;
this.timeUnit = timeUnit;
this.executorService.submit(new SelectorTask());
}
public boolean register(Process process) {
try {
registeredProcessesLock.lock();
return registeredProcesses.add(process);
} finally {
registeredProcessesLock.unlock();
}
}
public boolean unregister(Process process) {
try {
registeredProcessesLock.lock();
return registeredProcesses.remove(process);
} finally {
registeredProcessesLock.unlock();
}
}
public Collection<Process> select() throws InterruptedException {
HashSet<Process> selectedInputs = new HashSet<>();
Process firstProcess = readyProcesses.take();
selectedInputs.add(firstProcess);
Process nextProcess = null;
while ((nextProcess = readyProcesses.poll()) != null) {
selectedInputs.add(nextProcess);
}
return selectedInputs;
}
private class SelectorTask implements Runnable {
public void run() {
while (true) {
try {
registeredProcessesLock.lock();
Iterator<Process> it = registeredProcesses.iterator();
while (it.hasNext()) {
Process p = it.next();
try {
int available = p.getInputStream().available();
if (available > 0)
readyProcesses.add(p);
if (p.isAlive() == false) {
System.err.println("Not alive");
it.remove();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
} finally {
registeredProcessesLock.unlock();
}
try {
timeUnit.sleep(timeOut);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}