- 浏览: 434849 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (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程序时,有时候我们需要调用其他的诸如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 748http://blog.csdn.net/qq27659271 ... -
继承 静态 代码块 变量 构造函数等执行顺序
2014-02-23 13:24 10111.静态变量和静态代码块和类绑定,类初始化时执行 父 ... -
二进制 八进制 十六进制 无符号整数
2014-02-19 15:23 1881基础 八进制 0开头 十六进制 0x开头 0x ... -
深入理解java虚拟机_笔记1
2014-02-17 14:03 925运行时数据区域: 包 ... -
java断点续传
2014-01-23 10:05 829转自 http://www.ibm.com/dev ... -
java基础1_Class.forName() ClassLoader.loadClass() 和new
2013-08-27 09:29 2103Class.forName()等同与Clas ... -
java基础2_编译期和运行期
2013-08-26 13:58 1528有3个概念: 编译时 运行时 构建时 理解这3个概 ... -
eclipse快捷键
2013-07-03 11:35 826我自己常用的一些快 ... -
java基础_Object
2013-09-09 12:53 749java.lang.Object java.lang ... -
抽象类和接口
2013-06-25 13:22 956抽象类是对象的抽象,然接口是一种行为规范 抽象 ... -
内部类
2013-06-25 12:41 1130第十章 内部类 2013年6月23日 星期日 1 ... -
Callable和Future的简单使用
2013-05-06 13:31 1698import java.util.Random; im ... -
Class.forName 和 ClassLoader.loadClass的区别
2013-03-29 16:54 1286Class.forName("xx.xx&q ... -
java泛型
2013-03-08 13:52 895import java.util.ArrayList; ... -
synchronized关键字总结
2013-03-08 13:24 9531、synchronized关键字的作用域有二种: 1) 是 ... -
为什么在重写了equals()方法之后也必须重写hashCode()方法
2013-03-08 12:54 20233我们都知道Java语言是完全面向对象的,在java中,所有的 ... -
为什么byte取值是-128到127
2012-05-07 09:36 6378建议你baidu下“补码” ... -
static
2012-05-07 09:24 1151public class A{ static in ... -
log4j
2012-04-09 09:18 1173http://www.iteye.com/topic/3780 ... -
java RuntimeException
2012-03-16 09:02 12635总结了一下JAVA中常见的几种RuntimeExcept ...
相关推荐
`Process`对象的`waitFor()`方法会阻塞直到进程结束,返回值是进程的退出码: ```java int exitCode = process.waitFor(); System.out.println("Process exited with code: " + exitCode); ``` ### 6. 销毁进程 ...
Process类提供了多种方法来执行外部命令,例如exec()方法可以执行指定的命令,waitFor()方法可以等待外部进程的结束。 在Java Process中,Runtime类是一个重要的类,它提供了对Java虚拟机的访问接口。通过Runtime类...
process.waitFor(); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } } ``` 在上面的代码中,我们创建了一个名为`ShellExecutor`的类,其中的`main`方法用于执行shell命令。通过`...
process.waitFor(); ``` 5. **删除文件** - 使用`Runtime.getRuntime().exec()`删除文件时,必须包含命令解释器,例如: ```java Process process = Runtime.getRuntime().exec("cmd /c del f:\\aaa.doc"); `...
这可以通过调用`Process`对象的`waitFor()`方法来实现: ```java Process process = Runtime.getRuntime().exec("ping 192.168.1.1"); process.waitFor(); ``` 需要注意的是,如果命令的执行时间过长,`waitFor()`...
Process 类的API预览包括destroy()、exitValue()、getErrorStream()、getInputStream()、getOutputStream()、waitFor() 等方法。 五、进程的创建和管理 Process 对象可以通过 ProcessBuilder.start() 和 Runtime....
例如,可以使用`ProcessBuilder.start()`方法来启动一个新的进程,`Process.waitFor()`方法来等待进程完成,以及`Process.destroy()`方法来终止进程。此外,`Process`对象提供了访问进程输入、输出和错误流的方法,...
- 为了确保所有输出都被正确读取,并且外部进程已经完全结束,需要调用`Process.waitFor()`方法。 ```java process.waitFor(); ``` 4. **完整示例代码**: ```java public class GetProcessList { public ...
这可以通过调用`Process.waitFor()`方法来实现。 ##### 示例5:等待命令执行完成 ```java Process process = Runtime.getRuntime().exec("cmd /c dir"); BufferedReader bufferedReader = new BufferedReader( new...
`process.waitFor()`则是等待子进程完成后再往下执行。 #### 2. 执行DOS内部命令 若要执行DOS内部命令,可以采用两种方法: - **方法一**:将命令解释器包含在`exec()`方法的参数中。 - 在Windows NT上,可以写...
在上述示例中,`process.waitFor()`用于等待进程结束并返回退出码,`exitCode`表示命令执行的结果。 三、ProcessBuilder类 在某些情况下,Runtime类可能无法满足复杂的命令行参数需求,这时可以使用ProcessBuilder...
通过调用 Process 对象的 waitFor 方法,可以阻塞当前 JAVA 线程,直到命令执行完毕。 但是,需要注意的是,如果该命令是有标准输出或者是错误输出的话,必须在 waitFor 方法阻塞之前,通过读取 Process 对象的 ...
`process.waitFor()`方法会阻塞直到命令执行完毕。 对于更复杂的命令,如需要参数、环境变量或者管道操作,可以使用`ProcessBuilder`类。例如,下面的代码创建了一个`ProcessBuilder`实例,设置了命令和参数,并将...
process.waitFor(); ``` 为了实现定时任务,我们可以使用`java.util.concurrent.ScheduledExecutorService`。首先,定义一个方法来执行备份操作,然后将其添加到调度器中。以下是一个简单的例子: ```java import ...
在执行之后,可以使用`Process`对象的方法来管理这个子进程,比如`waitFor()`方法可以阻塞当前线程,直到子进程结束。 另外,文档中提到了使用批处理(Batch)文件进行操作。批处理文件通常包含一系列命令,可以一...
在执行命令后,需要通过`Process`对象的`waitFor()`方法等待命令执行完成,获取退出状态码。 ```java int exitCode = process.waitFor(); System.out.println("Command exited with code: " + exitCode); ``` 退出...
process.waitFor(); ``` 4. **资源管理**: - 在执行涉及文件操作的任务,如ZIP文件的解压缩,需要特别注意资源的释放。如果不正确地管理这些资源,可能会导致文件被占用而无法删除。例如,使用Java的ZIP模块...
解决的办法是,利用 Java 提供的 Process 类提供的方法让 Java 虚拟机截获被调用程序的 DOS 运行窗口的标准输出,在 waitfor() 命令之前读出窗口的标准输出缓冲区中的内容。 删除文件 在删除文件时,需要注意 ...
int exitCode = process.waitFor(); System.out.println("Process exited with code: " + exitCode); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } } ``` **解释** - `...