java调用脚本语言或其他进程(以Python为例)

很多时候,我们往往需要在java中调用其他脚本语言,或者是其他进程,来弥补java的一些不便之处.
万能的方式就是使用Process类了,当然针对Python还可以使用jython,但jython还是有诸多不便

String command = "python test.py";
Process pythonProcess = Runtime.getRuntime().exec(command);

Process的强大功能,就在于调用其他进程时,可以相互实现信息传递,基于java IO实现,调用者只需要熟悉java IO操作,即可调用.
我写了一个辅助类,以便于对进程之间的信息传递,实现策略为,将InputStream操作改为线程操作.具体代码如下:

package runtime;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
 * 将InputStream操作改为线程操作
 */
public class StreamThreadRead extends Thread{
    //存储读取的字符串
    private final StringBuffer sBuffer;
    //对应的输入流
    private final InputStream iStream;
    public StreamThreadRead(InputStream iStream){
        super();
        sBuffer = new StringBuffer();
        this.iStream = iStream;
    }
    @Override
    public void run() {
        BufferedReader bReader = new BufferedReader(new InputStreamReader(iStream));
        String str;
        try {
            while ((str = bReader.readLine()) != null) {
                sBuffer.append(str).append("\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public StringBuffer getsBuffer() {
        return sBuffer;
    }
    public InputStream getiStream() {
        return iStream;
    }   
}

这个便是辅助类啦,类如其名”进程IO传输”,不过准确来讲,已经实现进程简单管理了.
可以随心所欲的在java和脚本之间传递数据,贼爽啊!

package runtime;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;

/**
 * 进程数据传输对象
 */
public class ProcessIOTransport {
    private final BufferedWriter stout;
    private final StreamThreadRead stin;
    private final StreamThreadRead errin;
    private final Process process;

    /**
     * 构造一个ProcessIOTransport
     * @param process
     * @throws IOException 
     */
    public ProcessIOTransport(String command) throws IOException{
        process = Runtime.getRuntime().exec(command);
        stout = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
        stin = new StreamThreadRead(process.getInputStream());
        errin = new StreamThreadRead(process.getErrorStream());
        //设为后台线程
        stin.setDaemon(true);
        errin.setDaemon(true);
        //启动线程
        stin.start();
        errin.start();
        //监控进程
        new Thread(new Runnable(){
            @Override
            public void run() {
                while(stin.isAlive()||errin.isAlive()){
                    try {
                        Thread.sleep(300);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                process.destroy();
            }
        });
    }
    /**
     * 构造一个ProcessIOTransport,其中向进程中输入参数args
     * @param process
     * @param args
     * @throws IOException
     */
    public ProcessIOTransport(String command,String...args) throws IOException{
        this(command);
        write(args);
    }
    /**
     * 构造一个ProcessIOTransport,当前java线程等待进程运行结束
     * @param process
     * @param timeOut 最迟等待时间(ms)
     * @throws IOException
     */
    public ProcessIOTransport(String command,long timeOut) throws IOException{
        this(command,timeOut,new String[]{null});
    }
    /**
     * 构造一个ProcessIOTransport,当前java线程等待进程运行结束
     * @param process
     * @param timeOut 最迟等待时间(ms)
     * @param args 向进程中传入的参数
     * @throws IOException
     */
    public ProcessIOTransport(String command,long timeOut,String...args) throws IOException{
        this(command,args);
        long start = System.currentTimeMillis();
        long now = System.currentTimeMillis();
        while(now-start<timeOut&&(stin.isAlive()||errin.isAlive())){
            try {
                Thread.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            now = System.currentTimeMillis();
        }
    }

    /**
     * 向process写数据
     * @param args
     * @throws IOException
     */
    public void write(String...args) throws IOException {
        for(int i = 0;i<args.length;i++){
            if(args[i]!=null){
                stout.write(args[i]);
                stout.flush();
            }
        }
    }
    /**
     * 读取process的标准输出
     * @return
     */
    public String readStandard(){
        if(stin.isAlive()){
            return null;
        }else{
            return stin.getsBuffer().toString();
        }
    }
    /**
     * 读取process的错误输出
     * @return
     */
    public String readError(){
        if(stin.isAlive()){
            return null;
        }else{
            return stin.getsBuffer().toString();
        }
    }
}

最后我们测试一下吧:

package runtime;

import java.io.IOException;

public class Test {

    public static void main(String[] args) {
        String command = "python test.py";
        try {           
            ProcessIOTransport piot1 = new ProcessIOTransport(command,200,"write1\n","write2\n");
            ProcessIOTransport piot2 = new ProcessIOTransport(command,200,"write3\n");
            System.out.println(piot1.readStandard());
            System.out.println("---------------------");
            System.out.println(piot2.readStandard());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

测试的Python代码如下

#unicode=UTF-8  
print ('hello')
v = input()
print (v)
print ('xx')
print (3+6)
z = input()
print (z)
print (3+3+3+3+3+3+3+3+3+3/6+3+3+3+3)

测试结果:

hello
write1
xx
9
write2
39.5

---------------------
null

当然,由于进程或者脚本等待着输入,而java迟迟不给输出,那么java的子线程stin,sterr也不会结束,我们将得不到脚本或进程的输出,而是得到null.此处,我没有设置抛出异常,而是把stin,sterr设置为了后台线程,当主线程结束,stin,sterr也随之终止,process也随之destroy掉,避免进程或脚本一直等待输入而持续运行.

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值