java - 如何正确使用PipedInputStream和PipedOutputStream?
巴扎黑
巴扎黑 2017-04-17 16:42:28
[Java讨论组]
  1. 使用Apache Common Execs库封装AbstractCommonExecs
    测试类是GbkCommonExecs

  2. 完整代码参考 笔记: http://segmentfault.com/n/1330000004289920

  3. 为什么执行GbkCommonExecs没有输出(可能死锁了)

  4. 贴上相关截图

  5. 如果把PipedInputStream和PipedOutputStream的方式换掉,换成ByteArrayOutputStream的方式,就能够正常输出,参考笔记代码的注释代码。

  6. 应该怎么使用PipedInputStream和PipedOutputStream使得我能够每行读取标准输出并做解析,解析到我需要的内容。


UPDATE:
这个AbstractCommonExecs并不能获得脚本的错误输出,比如创建一个文件夹两次,第二次应该会提示类似目录已存在的错误,但是封装后的代码只能看到apache common execs的异常堆栈:


UPDATE:
尝试了LogOutputStream的方式,参考下面的答案,但是避免不了出现字符编码的问题。
ApacheCommonExec.java,https://gist.github.com/cb372/2224509
直接跑这样的代码就可以知道了。


UPDATE:
找到一个可以替代的库,https://github.com/zeroturnaround/zt-exec
从描述来看处理不少windows下遇到的问题,如参数为空的问题,编码的问题。

巴扎黑
巴扎黑

全部回复(2)
怪我咯

commons-exec 包中有 org.apache.commons.exec.LogOutputStream 类
可以通过继承该类实现一个实时输出的队列 读取阻塞队列里的内容来获取命令输出结果
Java管道流使用起来问题比较多,不太方便且控制不好容易出现IOException

PumpStreamHandler streamHandler = new PumpStreamHandler(CommandExecOutputStream);

public class CommandExecOutputStream extends LogOutputStream {
    
    static Logger logger = LoggerFactory.getLogger(CommandExecOutputStream.class);
    
    private BlockingQueue<String> queue;
    
    public CommandExecOutputStream(){
        
    }
    
    public CommandExecOutputStream(BlockingQueue<String> queue){
        this.queue = queue;
    }
    
    @Override
    protected void processLine(String line, int level) {
        try {
            logger.debug("{}",line);
            queue.put(line);
        } catch (InterruptedException e) {
            logger.error("命令执行过程输出InterruptedException",e);
        }
    }
}
PHP中文网

我自问自答,参考verifyJobPriority方法,需要对PipedInputStream流做关闭的动作。
所以,AbstractCommonExecs可以这么修改:

    PipedOutputStream outputStream = new PipedOutputStream();
    PipedInputStream pis = new PipedInputStream(outputStream);
    ByteArrayOutputStream errorStream = new ByteArrayOutputStream();
    PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream,errorStream);
    executor.setStreamHandler(streamHandler);
    int ret = executor.execute(cmdLine);
            
    BufferedReader br = new BufferedReader(new InputStreamReader(pis, getEncoding()));
    StringBuilder sb = new StringBuilder();
    String line = null;
    while((line = br.readLine()) != null) {
        sb.append(line+"\n");
        if(line.startsWith(getCodeInfokey())) {
            er.setCodeInfo(line);
        }
    }
    pis.close();
    String stdout = sb.toString();

注意这个pis.close()调用。

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号