今天用了下java.lang.Process类,只是初步的学习,并没有深入实践,因为感觉它的用途并不是很大,偶尔才可能用上,如果要经常使用它的人可以自行参考JDk文档。
对Process类的简要说明:
Process类是一个抽象类,方法都是抽象的,它封装了一个进程,也就是一个可执行的程序
该类提供进程的输入、执行输出到进程、等待进程的完成和检查进程的退出状态及销毁进程的方法
ProcessBuilder.start()和Runtime.exec方法创建一个本机进程并返回Process子类的一个实例,该实例可以控制进程并获取相关的信息
其它的概要请参考JDK文档
下面就开始举几个简单的示例:
(1)执行简单的DOS命令,如打开一个记事本
- package com.iwtxokhtd.other;
- import java.io.IOException;
- public class ProcessTest {
- public static void main(String[] args) {
- try {
- Process proc=Runtime.getRuntime().exec("notepad");
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- package com.iwtxokhtd.other;
- import java.io.IOException;
- public class ProcessTest {
- public static void main(String[] args) {
- try {
- Process proc=Runtime.getRuntime().exec("notepad");
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
package com.iwtxokhtd.other;
import java.io.IOException;
public class ProcessTest {
public static void main(String[] args) {
try {
Process proc=Runtime.getRuntime().exec("notepad");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
(2)使用它的其它构造方法执行相关的命令,如下例:
- package com.iwtxokhtd.other;
- import java.io.IOException;
- public class ProcessTest {
- public static void main(String[] args) {
- try {
- String exeFullPathName="C:/Program Files/Internet Explorer/IEXPLORE.EXE";
- String message="www.google.com";
- String []cmd={exeFullPathName,message};
- Process proc=Runtime.getRuntime().exec(cmd);
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- package com.iwtxokhtd.other;
- import java.io.IOException;
- public class ProcessTest {
- public static void main(String[] args) {
- try {
- String exeFullPathName="C:/Program Files/Internet Explorer/IEXPLORE.EXE";
- String message="www.google.com";
- String []cmd={exeFullPathName,message};
- Process proc=Runtime.getRuntime().exec(cmd);
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
package com.iwtxokhtd.other;
import java.io.IOException;
public class ProcessTest {
public static void main(String[] args) {
try {
String exeFullPathName="C:/Program Files/Internet Explorer/IEXPLORE.EXE";
String message="www.google.com";
String []cmd={exeFullPathName,message};
Process proc=Runtime.getRuntime().exec(cmd);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
执行上述命令可以打开Google网站
(3)列出系统正在运行的所有进程信息
- package com.iwtxokhtd.other;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStreamReader;
- public class ListAllProcessTest {
- //列出所有的进程信息
- public static void main(String[] args) {
- BufferedReader br=null;
- try {
- Process proc=Runtime.getRuntime().exec("tasklist");
- br=new BufferedReader(new InputStreamReader(proc.getInputStream()));
- @SuppressWarnings("unused")
- String line=null;
- System.out.println("打印所有正在运行的进程信息");
- while((line=br.readLine())!=null){
- System.out.println(br.readLine());
- }
- } catch (IOException e) {
- e.printStackTrace();
- }finally{
- if(br!=null){
- try {
- br.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }
- }
- package com.iwtxokhtd.other;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStreamReader;
- public class ListAllProcessTest {
- //列出所有的进程信息
- public static void main(String[] args) {
- BufferedReader br=null;
- try {
- Process proc=Runtime.getRuntime().exec("tasklist");
- br=new BufferedReader(new InputStreamReader(proc.getInputStream()));
- @SuppressWarnings("unused")
- String line=null;
- System.out.println("打印所有正在运行的进程信息");
- while((line=br.readLine())!=null){
- System.out.println(br.readLine());
- }
- } catch (IOException e) {
- e.printStackTrace();
- }finally{
- if(br!=null){
- try {
- br.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }
- }
package com.iwtxokhtd.other;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class ListAllProcessTest {
//列出所有的进程信息
public static void main(String[] args) {
BufferedReader br=null;
try {
Process proc=Runtime.getRuntime().exec("tasklist");
br=new BufferedReader(new InputStreamReader(proc.getInputStream()));
@SuppressWarnings("unused")
String line=null;
System.out.println("打印所有正在运行的进程信息");
while((line=br.readLine())!=null){
System.out.println(br.readLine());
}
} catch (IOException e) {
e.printStackTrace();
}finally{
if(br!=null){
try {
br.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
(4)判断一个具体的进程是否正在运行,如下例:
- package com.iwtxokhtd.other;
- import java.io.BufferedReader;
- import java.io.InputStreamReader;
- public class FindProcessExeTest
- {
- public static void main(String []args){
- if(findProcess("QQ.exe")){
- System.out.println("------判断指定的进程是否在运行------");
- System.out.println("QQ.exe该进程正在运行!");
- }else{
- System.out.println("------判断指定的进程是否在运行------");
- System.out.println("QQ.exe该进程没有在运行!");
- }
- }
- public static boolean findProcess(String processName){
- BufferedReader br=null;
- try{
- //下面这句是列出含有processName的进程图像名
- Process proc=Runtime.getRuntime().exec("tasklist /FI /"IMAGENAME eq "+processName+"/"");
- br=new BufferedReader(new InputStreamReader(proc.getInputStream()));
- String line=null;
- while((line=br.readLine())!=null){
- //判断指定的进程是否在运行
- if(line.contains(processName)){
- return true;
- }
- }
- return false;
- }catch(Exception e){
- e.printStackTrace();
- return false;
- }finally{
- if(br!=null){
- try{
- br.close();
- }catch(Exception ex){
- }
- }
- }
- }
- }
- package com.iwtxokhtd.other;
- import java.io.BufferedReader;
- import java.io.InputStreamReader;
- public class FindProcessExeTest
- {
- public static void main(String []args){
- if(findProcess("QQ.exe")){
- System.out.println("------判断指定的进程是否在运行------");
- System.out.println("QQ.exe该进程正在运行!");
- }else{
- System.out.println("------判断指定的进程是否在运行------");
- System.out.println("QQ.exe该进程没有在运行!");
- }
- }
- public static boolean findProcess(String processName){
- BufferedReader br=null;
- try{
- //下面这句是列出含有processName的进程图像名
- Process proc=Runtime.getRuntime().exec("tasklist /FI /"IMAGENAME eq "+processName+"/"");
- br=new BufferedReader(new InputStreamReader(proc.getInputStream()));
- String line=null;
- while((line=br.readLine())!=null){
- //判断指定的进程是否在运行
- if(line.contains(processName)){
- return true;
- }
- }
- return false;
- }catch(Exception e){
- e.printStackTrace();
- return false;
- }finally{
- if(br!=null){
- try{
- br.close();
- }catch(Exception ex){
- }
- }
- }
- }
- }
package com.iwtxokhtd.other;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class FindProcessExeTest
{
public static void main(String []args){
if(findProcess("QQ.exe")){
System.out.println("------判断指定的进程是否在运行------");
System.out.println("QQ.exe该进程正在运行!");
}else{
System.out.println("------判断指定的进程是否在运行------");
System.out.println("QQ.exe该进程没有在运行!");
}
}
public static boolean findProcess(String processName){
BufferedReader br=null;
try{
//下面这句是列出含有processName的进程图像名
Process proc=Runtime.getRuntime().exec("tasklist /FI /"IMAGENAME eq "+processName+"/"");
br=new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line=null;
while((line=br.readLine())!=null){
//判断指定的进程是否在运行
if(line.contains(processName)){
return true;
}
}
return false;
}catch(Exception e){
e.printStackTrace();
return false;
}finally{
if(br!=null){
try{
br.close();
}catch(Exception ex){
}
}
}
}
}
其它的用法可以参考JDK文档,这里就不一一举例,毕竟它用得不多。
(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");
- }
- }
- }