java 调用process

java调用process 有两种实现方法,一是使用Runtime类,二是使用Process类。

我在最近的项目里用的是Runtime类,接下来写下总结。

 

有图有真相(在网上学来一句话)


 1 package com.lee.demo;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.IOException;
 5 import java.io.InputStream;
 6 import java.io.InputStreamReader;
 7 
 8 public class RuntimeDemo01 {
 9 
10     public static void main(String[] args) {
11         String s;
12         StringBuilder sb = new StringBuilder();
13         InputStream fis = null;
14         try {
15             // Process process = Runtime.getRuntime().exec("ping localhost");
Process process = Runtime.getRuntime().exec(new String[]{"sh", "-c", XXXX});
// 注意,我将原来的15行注释掉了,变成了下面的写法。声明,我调用的command是Lunix下的命令,如果你用的是windows的话,不需要这么写。
// 为什么要使用这样的写法,因为项目需要考虑到单引号双引号等,转换加/的原因。
16 fis = process.getInputStream(); 17 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fis)); 18 while((s=bufferedReader.readLine()) != null) { 19 sb.append(s);
//sb.append(\n);
20 } 21 System.out.println(sb.toString()); 22 process.waitFor(); 23 System.out.println(process.exitValue()); 24 } catch (InterruptedException e) { 25 e.printStackTrace(); 26 } catch (IOException e) { 27 e.printStackTrace(); 28 } finally { 29 try { 30 fis.close(); 31 } catch (IOException e) { 32 e.printStackTrace(); 33 } 34 } 35 } 36 }

执行结果如下

使用法: ping [-t] [-a] [-n 要求数] [-l サイズ] [-f] [-i TTL] [-v TOS]            [-r ホップ数] [-s ホップ数] [[-j ホスト一覧] | [-k ホスト一覧]]            [-w タイムアウト] [-R] [-S ソースアドレス] [-4] [-6] ターゲット名オプション:    -t             中断されるまで、指定されたホストを Ping します。                   統計を表示して続行するには、Ctrl+Break を押してください。                   停止するには、Ctrl+C を押してください。    -a             アドレスをホスト名に解決します。    -n 要求数      送信するエコー要求の数です。    -l サイズ      送信バッファーのサイズです。    -f             パケット内の Don't Fragment フラグを設定します (IPv4 のみ)。    -i TTL         Time To Live です。    -v TOS         Type Of Service (IPv4 のみ。この設定はもう使用されておらず、                   IP ヘッダー内のサービス フィールドの種類に影響しません)。    -r ホップ数    指定したホップ数のルートを記録します (IPv4 のみ)。    -s ホップ数    指定したホップ数のタイムスタンプを表示します (IPv4 のみ)。    -j ホスト一覧  一覧で指定された緩やかなソース ルートを使用します                   (IPv4 のみ)。    -k ホスト一覧  一覧で指定された厳密なソース ルートを使用します                   (IPv4 のみ)。    -w タイムアウト                   応答を待つタイムアウトの時間 (ミリ秒) です。    -R             ルーティング ヘッダーを使用して逆ルートもテストします                   (IPv6 のみ)。    -S ソースアドレス                   使用するソース アドレスです。    -4             IPv4 の使用を強制します。    -6             IPv6 の使用を強制します。

如果你执行的命令是 ping localhost的话,那么是可以正常执行并返回黑屏下一样的结果的。

在这里说一下我遇到的几个坑。

首先,lunix下执行和windows下执行不一样。比如上面的例子中,ping这个命令,没有添加参数时,在执行结果中会打出黑屏下一样的提示信息,但是lunix下不行,在程序中需要process.getErrorStream(),这样才能得到一致的结果。

第二个坑,是要记得添加process.waitFor();这行代码,代码的意思是 线程一直到process结束再往下执行。如果不写这行代码,那么process执行的同时,线程在往下执行,到后面23行的代码会抛出error。此外,process.waitFor()代码要放在,对输入流的操作之后,因为每次输入流读取的大小是有限制的,如果超过最大值,而输入流中的内容没有被读取,那么久会发生阻塞,到时程序一直停在那里。

第三个坑,在上文中代码的第17行里,使用了匿名类的new InputStreamReader,在性能测试的时候,报错,can not open too many files,原因是InputStreamReader使用了之后,最后没有将他close。一定要在finally中将它close掉。

第四个坑,代码第18行,readLine()方法,大家很熟悉。我们看一下API中的定义。

public String readLine()
                throws IOException

Reads a line of text. A line is considered to be terminated by any one of a line feed ('\n'), a carriage return ('\r'), or a carriage return followed immediately by a linefeed.

Returns:
    A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached
Throws:
    IOException - If an I/O error occurs

 在returns中,明确写明,只返回内容,不会返回换行符号等。这就导致最后我们取得的内容是一行String,很长。我决定在19行后,加个换行符,这样就可以换行了。

 

接下来,简单说明一下Process类,要说的是,自jdk1.5起,官方建议,使用ProcessBuilder.start()来启动process

官方文档地址: https://docs.oracle.com/javase/8/docs/api/java/lang/Process.html

其实JDK中Runtime最终调用的是processbuilder。

processbuilder提供的功能更加丰富,可以设置工作目录,环境变量等。

推荐一篇文章,processBuilder介绍得很好。

http://www.cnblogs.com/taven/archive/2011/12/17/2291460.html

 

posted @ 2017-07-17 09:53  Mr.袋鼠  阅读(18167)  评论(0编辑  收藏  举报