关于Java调用外部程序即时输出的一些收获

        这几天做的项目里面,有一项是需要我在java的代码中调用外部的python程序并将python的输出结果实时地输出到java console中。按照网络上的教程来做,却发现没办法做到实时输出。后来经过不懈努力终于发现了原因。因此记录下来避免日后忘记。

        首先,基本的方法大家都懂,就是通过Jave的Process类来新建一个子进程。具体代码如下:(具体代码中周围需要加入的try/catch语句已省略)

String cmd = "Your command";
Process process = Runtime.getRuntime().exec(cmd);
			
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);  
BufferedReader br = new BufferedReader(isr);  
String line;

while((line = br.readLine()) != null ) {
	System.out.println(line);
	System.out.flush();
}
			
isr.close();  
br.close(); 
is.close();

       具体思路就是用一个InputStream来获取process的InputStream,然后用一个BufferedReader来装它,使用BufferedReader的readline函数实现逐行读取,并且在循环中输出每次读到的字符串。

        看上去很对很美好,不是吗?

        是的,例如调用系统的ping指令查看网络状况:

String cmd = "ping http://www.baidu.com"

        然后能够在java IDE中的console窗口里看到ping的情况。这时候我再换一个python文件试试。python代码如下:

#!/usr/bin/python

time = 10

while time > 0:
	print "Current number:" + str(time)
	temp = 9999999
	while temp>0: temp-=1
	time -= 1

        程序也很简单,就是输出"Current number: time", 其中time是从10到1. 中间有个temp的循环,是为了增加每次输出之间的间隔。如果这时候在命令行执行这段代码的话,大约每间隔1秒多就会输出一条:

Current number:10
Current number:9
Current number:8
Current number:7
Current number:6
Current number:5
Current number:4
Current number:3
Current number:2
Current number:1

       那么在java的console中能不能也这样显示呢?按理来说是没问题的。但是执行后你会发现,这些字符串在java的console中并不是1秒1个这样弹出来的,而是在python程序结束(即process结束后)一起弹出来的。一开始我以为是BufferedReader的缓冲区大小问题,但是无论怎么调整,都不能产生正确结果。然后我设置了断点单步执行,发现在每一个while循环中line都是被正确赋值的,然后java的console在debug的模式下居然是能一下一下输出的。这说明java这边似乎没有什么问题。

        然后我上网查找了些解决方法,有人说可能是进程阻塞的问题,但是我的process没有调用waitFor()方法。又有人说process有getInputStream()和getErrorStream()两个方法,分别获取输入流和错误流。如果单单只获取输入流的话可能造成子进程阻塞,原因是这两个输入流并不是相互独立的。因此需要再开一个线程同时读取错误流。但是我试过后依然无效。后来发现一点:使用ping的时候可能正常输出,但是调用python程序的时候就不行了,会不会是python本身的问题呢?于是我写了同样功能的C程序,发现依旧不能1秒输出1个。再后来,我无意中看到了这篇博文:

        Java调用外部程序解决方案

        里面那句“经过测试,我们发现一个问题,如果外部程序在输出信息时,没有用flush也会出现问题”点醒了我。我才发现原来是python和C程序中使用print或者printf输出也是有缓冲机制的。所以process的getInputStream()并不能立即获得输出结果(因为此时结果还保留在C或python进程输出的缓冲区中),所以需要在python中的print后面加入sys.stdout.flush()才行。如此,问题解决。

        总结一下,我认为自己在这里卡了这么久的原因,是自己对java、python等语言的缓冲机制仍不了解。在今后的学习中我会关注这方面的内容,搞清楚缓冲机制的原理、过程和作用,下次就不会再犯这类错误了。

        

        

        




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值