开发者社区> 问答> 正文

如何正确使用PipedInputStream和PipedOutputStream?

1.使用Apache Common Execs库封装AbstractCommonExecs
测试类是GbkCommonExecs
2.完整代码:

public abstract class AbstractCommonExecs {
 
        private Logger log = LoggerFactory.getLogger(AbstractCommonExecs.class);
        private static final String DEFAULT_ENCODING = "UTF-8";
        private String encoding = DEFAULT_ENCODING;
        private static final String DEFAULT_CODEINFO_KEY = "CODEINFO";
        private String codeInfokey = DEFAULT_CODEINFO_KEY;
        
        private String bin;
        private List<String> arguments;
        public AbstractCommonExecs(String bin, List<String> arguments) {
                this.bin = bin;
                this.arguments = arguments;
        }
        
        public ExecResult exec() throws CmdRunException{
                ExecResult er = new ExecResult();
                try {
                        Executor executor = getExecutor();
                        CommandLine cmdLine = getCommandLine();
                        log.info("Executing script {}",cmdLine.toString());
                        if(supportWatchdog()) {
                                executor.setWatchdog(getWatchdog());
                        }
                        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                        PipedOutputStream outputStream = new PipedOutputStream();
                        //ByteArrayOutputStream errorStream = new ByteArrayOutputStream();
                        PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream,errorStream);
                        executor.setStreamHandler(streamHandler);
                        int ret = executor.execute(cmdLine);
                        
                        BufferedReader br = new BufferedReader(new InputStreamReader(new PipedInputStream(outputStream), getEncoding()));
                        StringBuilder sb = new StringBuilder();
                        String line = null;
                        while((line = br.readLine()) != null) {
                                sb.append(line+"\n");
                                if(line.startsWith(getCodeInfokey())) {
                                        er.setCodeInfo(line);
                                }
                        }
                        
                        String stdout = sb.toString();
                        //String stdout = outputStream.toString(getEncoding());
                        String stderr = errorStream.toString(getEncoding());
                        er.setStderr(stderr);
                        log.info("output from script {} is {}", this.bin, stdout);
                        log.info("error output from script {} is {}", this.bin, stderr);
                        log.info("exit code from script {} is {}", this.bin, ret);
                        er.setStdout(stdout);
                        er.setExitCode(ret);
                        return er;
                } catch (ExecuteException e) {
                        throw new CmdRunException("", e);
                } catch (IOException e) {
                        throw new CmdRunException("", e);
                }
                
        }
 
        public Executor getExecutor() {
                Executor executor = new DefaultExecutor();
                executor.setWorkingDirectory(new File(this.bin).getParentFile());
                return executor;
        }
        public CommandLine getCommandLine() {
                String fullCommand = bin + join(arguments);
                if(isWindowSystem()) {
                        fullCommand = "cmd /c " + fullCommand;
                }
                
                return CommandLine.parse(fullCommand);
        }
        protected String join(List<String> arguments) {
                if(arguments == null || arguments.isEmpty()) {
                        return "";
                }
                StringBuilder sb = new StringBuilder();
                for(String arg : arguments) {
                        sb.append(" ").append(arg);
                }
                return sb.toString();
        }
        protected boolean isWindowSystem(){
                boolean isWindowSystem = false;
                Properties props=System.getProperties(); 
                String osName = props.getProperty("os.name");
                if(osName != null){
                        isWindowSystem = osName.contains("Windows") || osName.contains("windows");
                }
                //return isWindowSystem;
                return false; //交给apache commons exec来判断
        }
        
        /**
         * @return the encoding
         */
        public String getEncoding() {
                return encoding;
        }
 
        /**
         * @param encoding the encoding to set
         */
        public void setEncoding(String encoding) {
                this.encoding = encoding;
        }
        
        /**
         * @return the codeInfokey
         */
        public String getCodeInfokey() {
                return codeInfokey;
        }
 
        /**
         * @param codeInfokey the codeInfokey to set
         */
        public void setCodeInfokey(String codeInfokey) {
                this.codeInfokey = codeInfokey;
        }
 
        public abstract boolean supportWatchdog();
        public abstract ExecuteWatchdog getWatchdog();
}
 
//=====================
// Test class
/**
 * This file created at 2016年1月12日.
 *
 * Copyright (c) 2002-2016 Honey, Inc. All rights reserved.
 */
package com.honey.command;
 
import java.util.ArrayList;
import java.util.List;
 
import org.apache.commons.exec.ExecuteWatchdog;
 
import com.honey.proxy.helper.AbstractCommonExecs;
import com.honey.proxy.helper.ExecResult;
 
/**
 * <code>{@link GbkCommonExecs}</code>
 *
 * windows开发环境测试
 *
 * @author Honwhy
 */
public class GbkCommonExecs extends AbstractCommonExecs{
 
        /**
         * @param bin
         * @param arguments
         */
        public GbkCommonExecs(String bin, List<String> arguments) {
                super(bin, arguments);
        }
 
        /* (non-Javadoc)
         * @see com.bingosoft.proxy.helper.AbstractCommonExecs#supportWatchdog()
         */
        @Override
        public boolean supportWatchdog() {
                // TODO implement AbstractCommonExecs.supportWatchdog
                return false;
        }
 
        /* (non-Javadoc)
         * @see com.bingosoft.proxy.helper.AbstractCommonExecs#getWatchdog()
         */
        @Override
        public ExecuteWatchdog getWatchdog() {
                // TODO implement AbstractCommonExecs.getWatchdog
                return null;
        }
        
        public String getEncoding() {
                return "GBK";
        }
        public static void main(String[] args) {
                String bin = "ping";
                String arg1 = "127.0.0.1";
                List<String> arguments = new ArrayList<String>();
                arguments.add(arg1);
                AbstractCommonExecs executable = new GbkCommonExecs(bin, arguments);
                ExecResult er = executable.exec();
                System.out.println(er.getExitCode());
                System.out.println(er.getStdout());
                System.out.println(er.getStderr());
        }
}

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

4.如果把PipedInputStream和PipedOutputStream的方式换掉,换成ByteArrayOutputStream的方式,就能够正常输出,参考笔记代码的注释代码。
5.应该怎么使用PipedInputStream和PipedOutputStream使得我能够每行读取标准输出并做解析,解析到我需要的内容。
这个AbstractCommonExecs并不能获得脚本的错误输出,比如创建一个文件夹两次,第二次应该会提示类似目录已存在的错误,但是封装后的代码只能看到apache common execs的异常堆栈:
screenshot

展开
收起
蛮大人123 2016-03-10 14:09:32 3003 0
1 条回答
写回答
取消 提交回答
  • 我说我不帅他们就打我,还说我虚伪

    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);
            }
        }
    }
    2019-07-17 18:57:34
    赞同 1 展开评论 打赏
问答分类:
问答地址:
问答排行榜
最热
最新

相关电子书

更多
低代码开发师(初级)实战教程 立即下载
冬季实战营第三期:MySQL数据库进阶实战 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载