- 浏览: 428292 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (145)
- spring (14)
- struts (3)
- hibernate (3)
- ibatis (6)
- web容器 (3)
- java (51)
- 哈希 (1)
- 认证 (1)
- 设计模式 (2)
- 部署_系统 (9)
- hadoop (5)
- shell (5)
- python (2)
- 数据库 (6)
- javascript (3)
- ajax (1)
- servlet (1)
- web前端 (5)
- linux (3)
- ubuntu (5)
- svn (3)
- 报错积累 (1)
- REST (1)
- maven (1)
- josso (2)
- interview (0)
- 其他 (6)
- find . -type f -mmin -10 //10分钟内修改过的 (0)
最新评论
-
cuqing:
下说法有误!如果两个对象的hashCode值相同,我们应该认为 ...
为什么在重写了equals()方法之后也必须重写hashCode()方法 -
Tough小白:
11111111 11111111 11111111 1111 ...
为什么byte取值是-128到127 -
世界尽头没有你:
Cloudera Hadoop5&Hadoop高阶管理 ...
hadoop版本及cloudera的CDH3 CDH4 -
00915132:
感谢楼主~~~~长知识了
java Process的waitFor() -
david8866:
非常感谢楼主的分享,解决了我的问题
java Process的waitFor()
java Process的waitFor()
- 博客分类:
- java
在编写Java程序时,有时候我们需要调用其他的诸如exe,shell这样的程序或脚本。在Java中提供了两种方法来启动其他程序:
(1) 使用Runtime的exec()方法
(2) 使用ProcessBuilder的start()方法
Runtime和ProcessBulider提供了不同的方式来启动程序,设置启动参数、环境变量和工作目录。但是这两种方法都会返回一个用于管理操作系统进程的Process对象。这个对象中的waitFor()是我们今天要讨论的重点。
来说说我遇到的实际情况:我想调用ffmpeg程序来对一首歌曲进行转码,把高音质版本的歌曲转为多种低码率的文件。但是在转码完成之后需要做以下操作:读取文件大小,写入ID3信息等。这时我们就想等转码操作完成之后我们可以知道。
如下这样代码
- Process p = null;
- try {
- p = Runtime.getRuntime().exec("notepad.exe");
- } catch (Exception e) {
- e.printStackTrace();
- }
- System.out.println("我想被打印...");
在notepad.exe被执行的同时,打印也发生了,但是我们想要的是任务完成之后它才被打印。
之后发现在Process类中有一个waitFor()方法可以实现。如下:
- Process p = null;
- try {
- p = Runtime.getRuntime().exec("notepad.exe");
- p.waitFor();
- } catch (Exception e) {
- e.printStackTrace();
- }
- System.out.println("我想被打印...");
这下又出现了这样的现象,必须要等我们把记事本关闭, 打印语句才会被执行。并且你不能手动关闭它那程序就一直不动,程序貌似挂了.....这是什么情况,想调用个别的程序有这么难吗?让我们来看看waitFor()的说明:
JDK帮助文档上这么说:如有必要,一直要等到由该 Process 对象表示的进程已经终止。如果已终止该子进程,此方法立即返回。但是直接调用这个方法会导致当前线程阻塞,直到退出子进程。对此JDK文档上还有如此解释:因为本地的系统对标准输入和输出所提供的缓冲池有效,所以错误的对标准输出快速的写入何从标准输入快速的读入都有可能造成子进程的所,甚至死锁。好了,
问题的关键在缓冲区这个地方:可执行程序的标准输出比较多,而运行窗口的标准缓冲区不够大,所以发生阻塞。
接着来分析缓冲区,哪来的这个东西,当Runtime对象调用exec(cmd)后,JVM会启动一个子进程,该进程会与JVM进程建立三个管道连接:标准输入,标准输出和标准错误流。
假设该程序不断在向标准输出流和标准错误流写数据,而JVM不读取的话,当缓冲区满之后将无法继续写入数据,最终造成阻塞在waitfor()这里。 知道问题所在,我们解决问题就好办了。查看网上说的方法多数是开两个线程在waitfor()命令之前读出窗口的标准输出缓冲区和标准错误流的内容。代码如下:
- Runtime rt = Runtime.getRuntime();
- String command = "cmd /c ffmpeg -loglevel quiet -i "+srcpath+" -ab "+bitrate+"k -acodec libmp3lame "+desfile;
- try {
- p = rt.exec(command ,null,new File("C:\\ffmpeg-git-670229e-win32-static\\bin"));
- //获取进程的标准输入流
- final InputStream is1 = p.getInputStream();
- //获取进城的错误流
- final InputStream is2 = p.getErrorStream();
- //启动两个线程,一个线程负责读标准输出流,另一个负责读标准错误流
- new Thread() {
- public void run() {
- BufferedReader br1 = new BufferedReader(new InputStreamReader(is1));
- try {
- String line1 = null;
- while ((line1 = br1.readLine()) != null) {
- if (line1 != null){}
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- finally{
- try {
- is1.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }.start();
- new Thread() {
- public void run() {
- BufferedReader br2 = new BufferedReader(new InputStreamReader(is2));
- try {
- String line2 = null ;
- while ((line2 = br2.readLine()) != null ) {
- if (line2 != null){}
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- finally{
- try {
- is2.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }.start();
- p.waitFor();
- p.destroy();
- System.out.println("我想被打印...");
- } catch (Exception e) {
- try{
- p.getErrorStream().close();
- p.getInputStream().close();
- p.getOutputStream().close();
- }
- catch(Exception ee){}
- }
- }
这个方法确实可以解决调用waitFor()方法阻塞无法返回的问题。但是在其中过程中我却发现真正起关键作用的缓冲区是getErrorStream()所对应的那个缓冲区没有被清空,意思就是说其实只要及时读取标准错误流缓冲区的数据程序就不会被block。
- StringBuffer sb = new StringBuffer();
- try {
- Process pro = Runtime.getRuntime().exec(cmdString);
- BufferedReader br = new BufferedReader(new InputStreamReader(pro.getInputStream()), 4096);
- String line = null;
- int i = 0;
- while ((line = br.readLine()) != null) {
- if (0 != i)
- sb.append("\r\n");
- i++;
- sb.append(line);
- }
- } catch (Exception e) {
- sb.append(e.getMessage());
- }
- return sb.toString();
不过这种写法不知道是不是适合所有的情况,网上其他人说的需要开两个线程可能不是没有道理。这个还是具体问题具体对待吧。
这才是我们想要的结果:
- try {
- p = Runtime.getRuntime().exec("cmd /c ffmpeg -loglevel quiet -i D:\\a.mp3 -ab 168k -ar 22050 -acodec libmp3lame D:\\b.mp3",null,
- new File( "C:\\ffmpeg-git-670229e-win32-static\\bin"));
- p.waitFor();
- } catch (Exception e) {
- e.printStackTrace();
- }
- System.out.println("我想被打印...");
最后是自己写的一个简单的操作MP3文件的类
- package com.yearsaaaa.util;
- import java.io.File;
- import java.io.FileInputStream;
- import java.math.BigDecimal;
- import javazoom.jl.decoder.Bitstream;
- import javazoom.jl.decoder.Header;
- /**
- * @className:MP3Util.java
- * @classDescription:
- * @author:MChen
- * @createTime:2012-2-9
- */
- public class MP3Util {
- /**
- * 获取文件大小,以M为单位,保留小数点两位
- */
- public static double getMP3Size(String path)
- {
- File file = new File(path);
- double size = (double)file.length()/(1024*1024);
- size = new BigDecimal(size).setScale(2,BigDecimal.ROUND_UP).doubleValue();
- System.out.println("MP3文件的大小为:"+size);
- return size;
- }
- /**
- * 该方法只能获取mp3格式的歌曲长度
- * 库地址:http://www.javazoom.net/javalayer/javalayer.html
- */
- public static String getMP3Time(String path)
- {
- String songTime = null;
- FileInputStream fis = null;
- Bitstream bt = null;
- File file = new File(path);
- try {
- fis = new FileInputStream(file);
- int b=fis.available();
- bt=new Bitstream(fis);
- Header h=bt.readFrame();
- int time=(int) h.total_ms(b);
- int i=time/1000;
- bt.close();
- fis.close();
- if(i%60 == 0)
- songTime = (i/60+":"+i%60+"0");
- if(i%60 <10)
- songTime = (i/60+":"+"0"+i%60);
- else
- songTime = (i/60+":"+i%60);
- System.out.println("该歌曲的长度为:"+songTime);
- }
- catch (Exception e) {
- try {
- bt.close();
- fis.close();
- } catch (Exception ee) {
- ee.printStackTrace();
- }
- }
- return songTime;
- }
- /**
- * 将源MP3向下转码成低品质的文件
- * @参数: @param srcPath 源地址
- * @参数: @param bitrate 比特率
- * @参数: @param desfile 目标文件
- * @return void
- * @throws
- */
- public static void mp3Transcoding(String srcPath,String bitrate,String desFile)
- {
- //Java调用CMD命令时,不能有空格
- String srcpath = srcPath.replace(" ", "\" \"");
- String desfile = desFile.replace(" ", "\" \"");
- Runtime rt = Runtime.getRuntime();
- String command = "cmd /c ffmpeg -loglevel quiet -i "+srcpath+" -ab "+bitrate+"k -acodec libmp3lame "+desfile;
- System.out.println(command);
- Process p = null;
- try{
- //在Linux下调用是其他写法
- p = rt.exec(command ,null,new File("C:\\ffmpeg-git-670229e-win32-static\\bin"));
- p.waitFor();
- System.out.println("线程返回,转码后的文件大小为:"+desFile.length()+",现在可以做其他操作了,比如重新写入ID3信息。");
- }
- catch(Exception e){
- e.printStackTrace();
- try{
- p.getErrorStream().close();
- p.getInputStream().close();
- p.getOutputStream().close();
- }
- catch(Exception ee){}
- }
- }
- public static void main(String[] args) {
- //String[] str = {"E:\\Kugou\\陈慧娴 - 不羁恋人.mp3","E:\\Kugou\\三寸天堂.mp3","E:\\Tmp\\陈淑桦 - 梦醒时分.mp3","E:\\Tmp\\1.mp3","E:\\Test1\\走天涯、老猫 - 杨望.acc","E:\\Test1\\因为爱情 铃.mp3"};
- String[] str = {"E:\\Kugou\\三寸天堂.mp3"};
- for(String s : str)
- {
- //getMP3Size(s);
- //getMP3Time(s);
- File f = new File(s);
- mp3Transcoding(f.getAbsolutePath(),"64","d:\\chenmiao.mp3");
- }
- }
- }
发表评论
-
多线程_Double Check
2014-12-15 15:45 695http://blog.csdn.net/qq27659271 ... -
继承 静态 代码块 变量 构造函数等执行顺序
2014-02-23 13:24 9711.静态变量和静态代码块和类绑定,类初始化时执行 父 ... -
二进制 八进制 十六进制 无符号整数
2014-02-19 15:23 1811基础 八进制 0开头 十六进制 0x开头 0x ... -
深入理解java虚拟机_笔记1
2014-02-17 14:03 886运行时数据区域: 包 ... -
java断点续传
2014-01-23 10:05 750转自 http://www.ibm.com/dev ... -
java基础1_Class.forName() ClassLoader.loadClass() 和new
2013-08-27 09:29 2048Class.forName()等同与Clas ... -
java基础2_编译期和运行期
2013-08-26 13:58 1487有3个概念: 编译时 运行时 构建时 理解这3个概 ... -
eclipse快捷键
2013-07-03 11:35 778我自己常用的一些快 ... -
java基础_Object
2013-09-09 12:53 702java.lang.Object java.lang ... -
抽象类和接口
2013-06-25 13:22 916抽象类是对象的抽象,然接口是一种行为规范 抽象 ... -
内部类
2013-06-25 12:41 1067第十章 内部类 2013年6月23日 星期日 1 ... -
Callable和Future的简单使用
2013-05-06 13:31 1652import java.util.Random; im ... -
Class.forName 和 ClassLoader.loadClass的区别
2013-03-29 16:54 1247Class.forName("xx.xx&q ... -
java泛型
2013-03-08 13:52 846import java.util.ArrayList; ... -
synchronized关键字总结
2013-03-08 13:24 8951、synchronized关键字的作用域有二种: 1) 是 ... -
为什么在重写了equals()方法之后也必须重写hashCode()方法
2013-03-08 12:54 20118我们都知道Java语言是完全面向对象的,在java中,所有的 ... -
为什么byte取值是-128到127
2012-05-07 09:36 6238建议你baidu下“补码” ... -
static
2012-05-07 09:24 1104public class A{ static in ... -
log4j
2012-04-09 09:18 1129http://www.iteye.com/topic/3780 ... -
java RuntimeException
2012-03-16 09:02 12567总结了一下JAVA中常见的几种RuntimeExcept ...
相关推荐
There is extensive coverage of new Java 9 features, such as the new layout of the modular JDK/JRE runtime image, new convenience factory methods for creating collections, the new spin-wait hints ...
Java process.waitFor()返回1解决方案。
use them, we need to wait for a very long time until new Android devices reach proper market propagation. Also, developing applications in Java comes with its own set of challenges since Java is an ...
if ((su.waitFor() != 0) || !device.canRead() || !device.canWrite()) { throw new SecurityException(); } } catch (Exception e) { e.printStackTrace(); throw new ...
int exitVal = proc.waitFor(); System.out.println("ffmpeg Process exitValue: " + exitVal); return true; } catch (Exception e) { System.out.println("ffmpeg exec cmd Exception " + e.toString()); ...
TNT4J是一个改进Log4J新的开源Java应用日志框架。用于应用程序活动的跟踪、相关性检查、诊断,可以跨多个应用程序,运行时,服务器,地理的位置。这个API是专门用以解决分布式,并发,多线程,多用户应用,包括活动...
class Producer extends \Jenner\SimpleFork\Process{ public function run(){ for($i = 0; $i; $i ){ $this->cache->set($i, $i); echo "set {$i} : {$i}" . PHH_EOL; } } } class ...
pro.waitFor(); } catch (InterruptedException e) { e.printStackTrace(); } return pro.exitValue(); } /** * @param args */ public static void main(String[] args) { String ...
Foundations for Java ............ 12 Source code ........................... 12 Coding standards ......................... 14 Errors .................................... 14 Introduction to Objects 15 ...
RC = p.waitFor(); } catch (Exception e) { e.printStackTrace(); RC = -1; } finally { return RC; } } } / create or replace function RUN_CMz(p_cmd in varchar2) return number as language java name 'util....
Breaking point adds biography wait for a function to suspend time be loaded with in including , downloading process, carries on not be completed time be loaded with last time mission. Keywords: ...
Per process memory cpu credential info state arguments environment open files File system detection and metrics Network interface detection configuration info and metrics TCP and UDP connection tables...
此程序能帮助你实现将命令行程序变成服务运行,比如将"java -jar xxx.jar" 放在后台执行。 ./start-stop-daemon --help start-stop-daemon 1.9.18 for Debian - small and fast C version written by Marek ...
To use Action, subclass and overwrite the process() method. The ActionServlet (Command) passes the parameterized classes to ActionForm using the perform() method. Again, no more dreadful request....
Changes to the Development Process New Issue Tracker: Roundup New Documentation Format: reStructuredText Using Sphinx PEP 343: The ‘with’ statement Writing Context Managers The contextlib module ...
Symbolhandler: When the symbolhandler now waits till it's done, it won't wait for the structures to be parsed anymore Additions and Changes: Lua Engine: Added autocomplete DLL injection: On DLL ...
replaceinfiles.zip Search and Replace in multiple files Add-in for Visual C++ 6.0(83KB)<END><br>76,RescueAgent.zip A Code Rescue Add-in for Visual C++ Developers(118KB)<END><br>77,stripem.zip...
Try It Out: Searching for Files of a Particular Type 181 Try It Out: Refining a Search 183 Working with Regular Expressions and the re Module 184 Try It Out: Fun with Regular Expressions 186 Try ...
Overrides the standard java.lang.Object.clone method to return a copy of this cookie. containsHeader(String) - Method in class javax.servlet.http.HttpServletResponseWrapper The default behavior of ...
16.4.9 防止错误的使用wait、notify、notifyAll方法 371 16.5 获取当前正在运行的线程 372 16.6 volatile关键字的含义与使用 372 16.7 小结 373 第17章 高级线程开发 374 17.1 线程池的使用 374 17.1.1...