国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

[Java]使用Apache Commons Execs調(diào)用腳本

chnmagnus / 2324人閱讀

摘要:還有,需要支持字符編碼設(shè)置,在下對(duì)象調(diào)試程序很有幫助,因此,我們可以列表表示整個(gè)需求。第二種是無(wú)法設(shè)置字符編碼的,而第一種是獲得了整個(gè)標(biāo)準(zhǔn)輸出和錯(cuò)誤輸出后再設(shè)置字符編碼的。

概述

寫(xiě)這篇的主要目的是為了整理和記錄,歸檔以便以后查閱。

我之前在SF上提問(wèn)了一個(gè)問(wèn)題:如何正確使用PipedInputStream和PipedOutputStream

問(wèn)題中提到的Apache Commons Execs這個(gè)庫(kù),相比我們?cè)瓉?lái)使用原生的Runtime和Process有不少優(yōu)點(diǎn)。
對(duì)比我之前寫(xiě)過(guò)的代碼,總結(jié)一下:

簡(jiǎn)化路徑處理
如果要調(diào)用的腳本的路徑存在空格,Apache Commons Execs會(huì)自動(dòng)幫忙加上轉(zhuǎn)義字符

兼容Windows環(huán)境
使用原生Runtime和Process方式時(shí),必須手工為調(diào)用bat腳本加上cmd /c,比如把test.bat腳本拼接成cmd /c才向Runtime.exec方法傳入這個(gè)腳本作為第一個(gè)參數(shù)

支持超時(shí)設(shè)置
原生的Runtime和Process并沒(méi)有直接支持超時(shí)的設(shè)置,但網(wǎng)上也有在原生基礎(chǔ)上做的超時(shí)功能的封裝,大概是基于循環(huán)定期檢查的機(jī)制。在SF上也有類(lèi)似的文章,其中的代碼大可參考一下,我要提醒的是,需要注意異步線程不能給及時(shí)返回結(jié)果的問(wèn)題。

在我的項(xiàng)目需求中,規(guī)定要獲得腳本的退出碼,標(biāo)準(zhǔn)輸出、錯(cuò)誤輸出。另外,還有可能要從標(biāo)注輸出中解析得到一個(gè)描述成功或失敗的結(jié)果,大概就是過(guò)濾腳本的標(biāo)準(zhǔn)輸出,捕獲感興趣的某一行,最后要預(yù)留超時(shí)設(shè)置的接口。還有,需要支持字符編碼設(shè)置,在Windows下對(duì)象調(diào)試程序很有幫助,因此,我們可以列表表示整個(gè)需求。

序號(hào) 需求 是否必須
1 退出碼、標(biāo)準(zhǔn)輸出、錯(cuò)誤輸出
2 獲得腳本提供的結(jié)果描述
3 設(shè)置超時(shí)
4 設(shè)置字符編碼
設(shè)計(jì)思路 1. 定義抽象類(lèi)預(yù)制整體流程
public abstract class AbstractCommonExecs {
    private String bin; //腳本
    private List arguments; //參數(shù)
    
    //Constructor method
    
    //封裝返回結(jié)果
    public ExecResult exec() throws IOException {
        try{
            Executor executor = getExecutor();  //執(zhí)行線程
            CommandLine cmdLine = getCommandLine(); //腳本命令參數(shù)等
            if(supportWatchdog()) { //是否支持監(jiān)視 用于設(shè)置超時(shí)等
                executor.setWatchdog(getWatchdog());    
            }
            executor.setStreamHandler(streamHandler);   //設(shè)置處理標(biāo)注輸出和錯(cuò)誤輸出的Handler
            int ret = executor.execute(cmdLine);    //獲得退出碼
        }catch(ExecuteException e) {
            int ret = e.getExitValue(); //如果出現(xiàn)異常還能獲得退出碼 關(guān)于這個(gè)仔細(xì)想想
        }
    }    
}

1.1 抽象類(lèi)接收腳本和參數(shù),類(lèi)型和形式還可以是別的形式

1.2 對(duì)外提供的exec方法返回的是退出碼、標(biāo)準(zhǔn)輸出、錯(cuò)誤輸出和腳本提供的結(jié)果描述

1.3 通過(guò)getXXX方法的形式可以將具體的實(shí)現(xiàn)交給具體實(shí)現(xiàn)類(lèi)來(lái)完成

2. 如何處理輸出

為了從Executor中獲得標(biāo)準(zhǔn)輸出和錯(cuò)誤輸出,是需要向Executor傳入一個(gè)streamHandler的是,這是一個(gè)基于字節(jié)流式的Handler,為了支持字符編碼的設(shè)計(jì),
最終處理時(shí)我們還需要將它轉(zhuǎn)成字符流并設(shè)置目標(biāo)字符編碼,比如在Windows開(kāi)發(fā)環(huán)境下設(shè)置為GBK

executor.setStreamHandler(streamHandler);   //設(shè)置處理標(biāo)注輸出和錯(cuò)誤輸出的Handler

這里先提兩種非常有效的做法,一種是基于ByteArrayOutStream的,一種是官方封裝的LogOutputStream。第一種,

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();  
ByteArrayOutputStream errorStream = new ByteArrayOutputStream();  

PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream,errorStream);  

executor.setStreamHandler(streamHandler);  

exec.execute(cmdline);  

String out = outputStream.toString("gbk");  //設(shè)置編碼

String error = errorStream.toString("gbk"); //設(shè)置編碼

第二種,參考這個(gè)答案。

第二種是無(wú)法設(shè)置字符編碼的,而第一種是獲得了整個(gè)標(biāo)準(zhǔn)輸出和錯(cuò)誤輸出后再設(shè)置字符編碼的。
如果采用這種方式,為了滿足從標(biāo)準(zhǔn)輸出解析某個(gè)特殊結(jié)果是需要對(duì)這個(gè)標(biāo)準(zhǔn)輸出做切分,再循環(huán)判斷的。

最后我采用的是PipedInputStreamPipedOutStream的方式,這也是為什么會(huì)有這個(gè)問(wèn)題如何正確使用PipedInputStream和PipedOutputStream
。為了讓處理標(biāo)注輸出、錯(cuò)誤輸出和結(jié)果描述看起來(lái)比較統(tǒng)一,我使用了回調(diào)的方式。

3. 回調(diào)方式處理
private void readInputStream(PipedInputStream pis, OutputCallback ...cbs) throws IOException {
    BufferedReader br = new BufferedReader(new InputStreamReader(pis, getEncoding()));
    String line = null;
    while((line = br.readLine()) != null) {
        for(OutputCallback cb : cbs) {
            cb.parse(line); //這里可以獲得結(jié)果描述
        }
    }
}
4. 說(shuō)明

整體思路上的抽象已經(jīng)做到了,但是還不夠徹底,抽象類(lèi)exec方法體內(nèi)業(yè)務(wù)邏輯還是過(guò)于耦合的。

完整代碼

ExecResult代碼,

public class ExecResult {

    private int exitCode;
    private String stdout;
    private String stderr;
    private String codeInfo;
    //getter and setter
}    

OutputCallback接口代碼,

public interface OutputCallback {
    public void parse(String line);
}

AbstractCommonExecs代碼,

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 String bin;
    private List arguments;
    public AbstractCommonExecs(String bin, List arguments) {
        this.bin = bin;
        this.arguments = arguments;
    }
    
    public ExecResult exec() throws IOException{
        ExecResult er = new ExecResult();
        //ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        PipedOutputStream outputStream = new PipedOutputStream();
        PipedInputStream pis = new PipedInputStream(outputStream);
        ByteArrayOutputStream errorStream = new ByteArrayOutputStream();
        CodeInfoCallback codeInfoCb = new CodeInfoCallback();
        StdOutputCallback stdoutCb = new StdOutputCallback();
        ErrorOutputCallback stderrCb = new ErrorOutputCallback();
        String stdout = null;
        String stderr = null;
        try {
            Executor executor = getExecutor();
            CommandLine cmdLine = getCommandLine();
            log.info("Executing script {}",cmdLine.toString());
            if(supportWatchdog()) {
                executor.setWatchdog(getWatchdog());
            }
            PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream,errorStream);
            executor.setStreamHandler(streamHandler);
            int ret = executor.execute(cmdLine);
            
            readInputStream(pis, stdoutCb, codeInfoCb);
            pis.close();
            readErrorStream(errorStream, stderrCb);
            stdout = join(stdoutCb.getLines());
            stderr = stderrCb.getErrors();
            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.setStderr(stderr);
            er.setCodeInfo(codeInfoCb.getCodeInfo());
            er.setExitCode(ret);
            return er;
        } catch (ExecuteException e) {
            if(pis != null) {
                readInputStream(pis, stdoutCb, codeInfoCb);
                pis.close();
            }
            if(errorStream != null) {
                readErrorStream(errorStream, stderrCb);
            }
            stdout = join(stdoutCb.getLines());
            stderr = stderrCb.getErrors();
            int ret = e.getExitValue();
            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.setStderr(stderr);
            er.setCodeInfo(codeInfoCb.getCodeInfo());
            er.setExitCode(ret);
            return er;
        }
        
    }
    /**
     * 接口回調(diào)的方式解析腳本的錯(cuò)誤輸出
     * @param baos
     * @param cbs
     * @throws IOException
     */
    private void readErrorStream(ByteArrayOutputStream baos, OutputCallback ...cbs) throws IOException {
        String err =  baos.toString(getEncoding());
        for(OutputCallback cb : cbs) {
            cb.parse(err);
        }
    }
    /**
     * 接口回調(diào)的方式解析腳本的標(biāo)準(zhǔn)輸出
     * @param pis
     * @param cbs
     * @throws IOException
     */
    private void readInputStream(PipedInputStream pis, OutputCallback ...cbs) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(pis, getEncoding()));
        String line = null;
        while((line = br.readLine()) != null) {
            for(OutputCallback cb : cbs) {
                cb.parse(line);
            }
        }
    }
    public Executor getExecutor() {
        Executor executor = new DefaultExecutor();
        executor.setWorkingDirectory(new File(this.bin).getParentFile());
        return executor;
    }
    public CommandLine getCommandLine() {
        String fullCommand = bin + join(arguments);        
        return CommandLine.parse(fullCommand);
    }
    protected String join(List arguments) {
        if(arguments == null || arguments.isEmpty()) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        for(String arg : arguments) {
            sb.append(" ").append(arg);
        }
        return sb.toString();
    }
    
    /**
     * @return the encoding
     */
    protected String getEncoding() {
        return encoding;
    }

    /**
     * @param encoding the encoding to set
     */
    public void setEncoding(String encoding) {
        this.encoding = encoding;
    }
    
    /**
     * @return the bin
     */
    protected String getBin() {
        return bin;
    }

    /**
     * @param bin the bin to set
     */
    public void setBin(String bin) {
        this.bin = bin;
    }

    /**
     * @return the arguments
     */
    protected List getArguments() {
        return arguments;
    }

    /**
     * @param arguments the arguments to set
     */
    public void setArguments(List arguments) {
        this.arguments = arguments;
    }

    public abstract boolean supportWatchdog();
    public abstract ExecuteWatchdog getWatchdog();
}
測(cè)試 1. 支持字符編碼設(shè)置的測(cè)試
public class GbkCommonExecs extends AbstractCommonExecs{

    /**
     * @param bin
     * @param arguments
     */
    public GbkCommonExecs(String bin, List 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;
    }
    
    //提供這個(gè)編碼即可
    public String getEncoding() {
        return "GBK";
    }
    public static void main(String[] args) throws IOException {
        String bin = "ping";
        String arg1 = "127.0.0.1";
        List arguments = new ArrayList();
        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());
    }

}
2. 支持超時(shí)設(shè)置的測(cè)試

設(shè)置監(jiān)視狗就能設(shè)置超時(shí)

public class TimeoutCommonExecs extends AbstractCommonExecs{

    private Logger log = LoggerFactory.getLogger(TimeoutCommonExecs.class);
    
    private long timeout = 10 * 1000; // 10 seconds
    public TimeoutCommonExecs(String bin, List arguments) {
        super(bin, arguments);
    }
    public TimeoutCommonExecs(String bin, List arguments, long timeout) {
        super(bin, arguments);
        this.timeout = timeout;
    }
    public boolean supportWatchdog() {
        return true; // 使用監(jiān)視狗 監(jiān)視腳本執(zhí)行超時(shí)的情況
    }
    public ExecuteWatchdog getWatchdog() {
        ExecuteWatchdog watchdog = new ExecuteWatchdog(this.timeout);
        return watchdog;
    }

    /**
     * @return the timeout
     */
    public long getTimeout() {
        return timeout;
    }

    /**
     * @param timeout the timeout to set
     */
    public void setTimeout(long timeout) {
        this.timeout = timeout;
    }
    
}

為了方便在Windows下測(cè)試

public class TimeoutGbkCommonExecs extends TimeoutCommonExecs{

    public TimeoutGbkCommonExecs(String bin, List arguments, long timeout) {
        super(bin, arguments, timeout);
        
    }
    //字符編碼設(shè)置
    public String getEncoding() {
        return "GBK";
    }
    public static void main(String[] args) throws IOException {
        String bin = "ping";
        String arg1 = "-t";   //不斷ping
        String arg2 = "127.0.0.1";
        List arguments = new ArrayList();
        arguments.add(arg1);
        arguments.add(arg2);
        AbstractCommonExecs executable = new TimeoutGbkCommonExecs(bin, arguments, 5 * 1000);
        ExecResult er = executable.exec();
        System.out.println(er.getExitCode());
        System.out.println(er.getStdout());
        System.out.println(er.getStderr());
    }

}

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/65396.html

相關(guān)文章

  • hudson+gradle+git+maven(非必選)持續(xù)集成 (二)

    摘要:第二集非必選持續(xù)集成編譯打包部署到線上環(huán)境集成前言在持續(xù)集成第一集中講解了關(guān)于如果編譯,打包,發(fā)布包到私服。在下面一集中,也就是第二集中,開(kāi)始講解如何持續(xù)集成可運(yùn)行的服務(wù)包到測(cè)試和正式環(huán)境。 第二集 hudson+gradle+git+maven(非必選)持續(xù)集成編譯,打包,部署到線上環(huán)境集成 前言 在持續(xù)集成第一集中,講解了關(guān)于如果編譯,打包,發(fā)布jar包到maven私服。在下面一集...

    william 評(píng)論0 收藏0
  • Tomcat 學(xué)習(xí)筆記(2) - 使用 jsvc 啟動(dòng)tomcat

    摘要:操作系統(tǒng)只用權(quán)限才能監(jiān)聽(tīng)已下的端口。雖然我們可以讓啟動(dòng)后以用戶的權(quán)限工作。我們還可以指定啟動(dòng)是的總之我們可以更精細(xì)的控制的運(yùn)行方式。只有該版本的是綁定到二進(jìn)制發(fā)行版中。這意味著它要與該版本的一同使用。 jsvc 是個(gè)什么是么高端武器呢 全稱(chēng):Java Service 還是沒(méi)有弄明白是什么,那就繼續(xù)往下看。 我們贊不討論 tomcat 應(yīng)不應(yīng)該運(yùn)行在80端口上。 假如我們有需求,需要 ...

    leoperfect 評(píng)論0 收藏0
  • 排名前16的Java工具類(lèi)

    摘要:在中,工具類(lèi)定義了一組公共方法,這篇文章將介紹中使用最頻繁及最通用的工具類(lèi)。另外,工具類(lèi),根據(jù)阿里開(kāi)發(fā)手冊(cè),包名如果要使用不能帶,工具類(lèi)命名為 在Java中,工具類(lèi)定義了一組公共方法,這篇文章將介紹Java中使用最頻繁及最通用的Java工具類(lèi)。以下工具類(lèi)、方法按使用流行度排名,參考數(shù)據(jù)來(lái)源于Github上隨機(jī)選取的5萬(wàn)個(gè)開(kāi)源項(xiàng)目源碼。 一. org.apache.commons.io....

    android_c 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<