Android执行程序或脚本的方法
Java中提供了两种方法来执行程序或脚本:
(1) 使用Runtime的exec()方法
(2) 使用ProcessBuilder的start()方法
ProcessBuilder.start() 和 Runtime.exec() 方法都被用来创建一个操作系统进程(执行命令行操作),并返回 Process 子类的一个实例,该实例可用来控制进程状态并获得相关信息。
1.调用ProcessBuilder的构造函数后执行start():
1 Process process = new ProcessBuilder("/system/bin/ping").redirectErrorStream(true).start(); 2 OutputStream stdout = process.getOutputStream(); 3 InputStream stdin = process.getInputStream(); 4 BufferedReader reader = new BufferedReader(new InputStreamReader(stdin)); 5 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdout));
2.用Runtime.getRuntime().exec()方法执行:
1 Process process = Runtime.getRuntime().exec("/system/bin/ping"); 2 OutputStream stdout = process.getOutputStream(); 3 InputStream stderr = process.getErrorStream(); 4 InputStream stdin = process.getInputStream(); 5 BufferedReader reader = new BufferedReader(new InputStreamReader(stdin)); 6 BufferedReader err= new BufferedReader(new InputStreamReader(stderr)); 7 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdout));
使用ProcessBuilder,可以通过redirectErrorStream(true)将错误输出流转移到标准输出流中,这样使用一次process.getInputStreamReader()就能读出该进程的所有输出。
而使用Runtime.getRuntime().exec()方法时,错误的输出流还需通过process.getErrorStream()来获得。
waitFor方法
ProcessBuilder.start() 和 Runtime.exec() 方法创建Process 子类的一个实例。 程序主进程会等待process一定的时间,但是时间很少,可能process根本无法完成工作就结束了。 因此,针对使用较长时间做工作的process,就需要调用waitFor方法。 该方法会引起当前Thread等待,直到process中断。
此方法返回的退出值的过程。按照惯例,0表示正常终止。
下面是一个进程执行后销毁的类:
1 import java.io.InputStream; 2 import java.io.OutputStream; 3 4 public class ProcessModel { 5 6 /** 7 * 通过Android底层实现进程关闭 8 * 9 * @param process 10 */ 11 public static void killProcess(Process process) { 12 int pid = getProcessId(process.toString()); 13 if (pid != 0) { 14 try { 15 android.os.Process.killProcess(pid); 16 } catch (Exception e) { 17 try { 18 process.destroy(); 19 } catch (Exception ex) { 20 } 21 } 22 } 23 } 24 25 /** 26 * 获取当前进程的ID 27 * 28 * @param str 29 * @return 30 */ 31 public static int getProcessId(String str) { 32 try { 33 int i = str.indexOf("=") + 1; 34 int j = str.indexOf("]"); 35 String cStr = str.substring(i, j).trim(); 36 return Integer.parseInt(cStr); 37 } catch (Exception e) { 38 return 0; 39 } 40 } 41 42 43 /** 44 * 关闭进程的所有流 45 * 46 * @param process 47 */ 48 public static void closeAllStream(Process process) { 49 try { 50 InputStream in = process.getInputStream(); 51 if (in != null) 52 in.close(); 53 } catch (Exception e) { 54 e.printStackTrace(); 55 } 56 try { 57 InputStream in = process.getErrorStream(); 58 if (in != null) 59 in.close(); 60 } catch (Exception e) { 61 e.printStackTrace(); 62 } 63 try { 64 OutputStream out = process.getOutputStream(); 65 if (out != null) 66 out.close(); 67 } catch (Exception e) { 68 e.printStackTrace(); 69 } 70 } 71 72 /** 73 * 销毁一个进程 74 * 75 * @param process 76 */ 77 public static void processDestroy(Process process) { 78 if (process != null) { 79 try { 80 if (process.exitValue() != 0) { 81 closeAllStream(process); 82 killProcess(process); 83 } 84 } catch (IllegalThreadStateException e) { 85 closeAllStream(process); 86 killProcess(process); 87 } 88 } 89 } 90 91 92 /** 93 * 通过线程进行异步销毁 94 * 95 * @param process 96 */ 97 public static void asyncProcessDestroy(final Process process) { 98 Thread thread = new Thread(new Runnable() { 99 @Override 100 public void run() { 101 processDestroy(process); 102 } 103 }); 104 thread.setDaemon(true); 105 thread.start(); 106 } 107 }
为了防止主控程序被waitfor方法阻塞,需要自己新建线程来处理Process流
1 Process p = Runtime.getRuntime().exec(cmd); 2 3 StreamGobbler errorGobbler = new StreamGobbler(p.getErrorStream(), "ERROR"); 4 5 // kick off stderr 6 errorGobbler.start(); 7 8 StreamGobbler outGobbler = new StreamGobbler(p.getInputStream(), "STDOUT"); 9 // kick off stdout 10 outGobbler.start(); 11 12 p.waitFor();
1 2 import java.io.BufferedReader; 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.InputStreamReader; 6 import java.io.OutputStream; 7 import java.io.PrintWriter; 8 9 import com.sdc.callmaxent.util.FileUtil; 10 11 /** 12 * 用于处理Runtime.getRuntime().exec产生的错误流及输出流 13 * @author shaojing 14 * 15 */ 16 public class StreamGobbler extends Thread { 17 InputStream is; 18 String type; 19 OutputStream os; 20 21 StreamGobbler(InputStream is, String type) { 22 this(is, type, null); 23 } 24 25 StreamGobbler(InputStream is, String type, OutputStream redirect) { 26 this.is = is; 27 this.type = type; 28 this.os = redirect; 29 } 30 31 public void run() { 32 InputStreamReader isr = null; 33 BufferedReader br = null; 34 PrintWriter pw = null; 35 try { 36 if (os != null) 37 pw = new PrintWriter(os); 38 39 isr = new InputStreamReader(is); 40 br = new BufferedReader(isr); 41 String line=null; 42 while ( (line = br.readLine()) != null) { 43 if (pw != null) 44 pw.println(line); 45 System.out.println(type + ">" + line); 46 } 47 48 if (pw != null) 49 pw.flush(); 50 } catch (IOException ioe) { 51 ioe.printStackTrace(); 52 } finally{ 53 FileUtil.close(pw); 54 FileUtil.close(br); 55 FileUtil.close(isr); 56 } 57 } 58 }
ProcessBuilder.start() 和 Runtime.exec() 方法都被用来创建一个操作系统进程(执行命令行操作),并返回 Process 子类的一个实例,该实例可用来控制进程状态并获得相关信息。