`
lzhnightwind
  • 浏览: 23397 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

在java应用中如何用Process和ProcessBuilder 执行命令?

阅读更多
分三个点类总结下,希望对有相似问题的人有所帮助!
1,如何执行,如何用ProcessBuilder来简化操作

2,如果调用外部java服务,如何在销毁进程的同时关闭它开启的外部服务?

3,如何获得执行进程的PID

 

 

1,如何执行,如何用ProcessBuilder来简化操作

ProcessBuilder(http://java.sun.com/j2se/1.5.0/docs/api/java/lang/ProcessBuilder.html)有个简单的例子。

ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg1", "myArg2");
 Map<String, String> env = pb.environment();
 env.put("VAR1", "myValue");
 env.remove("OTHERVAR");
 env.put("VAR2", env.get("VAR1") + "suffix");
 pb.directory("myDir");
 Process p = pb.start();

这个例子描述了如何执行一个命令,但是如果你想从命令行读取输入输出呢?

假设我们想执行如下命令

Ipconfig –all

我们可以做如下改进

写道
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ProcessExec {

private Process process;

public void execute()
throws InterruptedException, IOException {
List<String> command = new ArrayList<String>();
command.add( "cmd.exe" );
command.add( "/c" );
command.add( "ipconfig -all" );

// 执行命令
ProcessBuilder pb = new ProcessBuilder( ( command ) );
process = pb.start();

// 异步读取输出
InputStream inputStream = process.getInputStream();
InputStream errorStream = process.getErrorStream();

ExecutorService service = Executors.newFixedThreadPool( 2 );

ResultStreamHandler inputStreamHandler = new ResultStreamHandler( inputStream );
ResultStreamHandler errorStreamHandler = new ResultStreamHandler( errorStream );

service.execute( inputStreamHandler );
service.execute( errorStreamHandler );

process.waitFor();
service.shutdownNow();
}

class ResultStreamHandler
implements Runnable {
private InputStream inputStream;

ResultStreamHandler( InputStream inputStream ) {
this.inputStream = inputStream;
}

public void run() {

BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader( new InputStreamReader( inputStream ) );
String line = null;

while ( ( line = bufferedReader.readLine() ) != null ) {
System.out.println( line );
}
}
catch ( Throwable t ) {
}
finally {
try {
bufferedReader.close();
}
catch ( IOException e ) {
}
}
}

}
}

 

现在我们可以异步读取输出了,但其方式比较单一,我们可不可以直接输出到一个指定文件呢?

jdk1.7起,ProcessBuilder增加Redirect来方便我们处理这个问题

1,输出有output, error两个流,输入有input流,相应的在这我们要创建3个文件

写道
File outputs = new File("C:/output.log");

File errors = new File("C:/error.log");

File input = new File("C:/input.txt");

 

2创建input.txt文件,输入一下命令

Ipconfig –all

确定all后面有回车符

3 创建一个ProcessBuilder实例,指定“cmd”作为参数,表示我们想执行一个window命令

 

写道

 

ProcessBuilder pb = newProcessBuilder("cmd");

 

4 Redirect输入输出流到不同的文件

写道
pb.redirectInput(commands);

pb.redirectError(errors);

pb.redirectOutput(output);

 

 

 

5 最后,执行命令

 

写道

 

pb.start();

 

 

需要注意的是start必须在redirct设定后才调用

 

ProcessBuilder还有一些使用的方法

比如ProcessBuilder.Redirect.appendTo

这样每次输出到指定文件都追加到后面而不是覆盖

 

写道

 

pb.redirectInput(ProcessBuilder.Redirect.appendTo( outputs ));

 

 

比较有用的还有inheritIO(), 调用这个方法可以redirect被执行命令的输入输出流到当前java进程的输入输出流,也就是说,如果你用eclipse执行,你在console里就可以看到输入输出。

 

2,如果调用外部java服务,如何在销毁进程的同时关闭它开启的外部服务?

有时候或许我们会执行一个外部的java应用

如:java –jar D:\\test.jar

假设test.jar 一旦启动会一直运行,那么问题来了,当process被销毁时,如何关闭这个外部进程呢?

有个bug专门描述了这个问题

http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4770092

可以看出没有什么好的解决办法

但有时我们就想用这个功能,怎么办?

或许我们可以使用jdk自带的tools.jar

 

这个程序遍历虚拟机上所有的java程序,提取他们main class名,如果和指定的main class名匹配,则返回pid

写道
import sun.jvmstat.monitor.HostIdentifier;
import sun.jvmstat.monitor.MonitorException;
import sun.jvmstat.monitor.MonitoredHost;
import sun.jvmstat.monitor.MonitoredVm;
import sun.jvmstat.monitor.MonitoredVmUtil;
import sun.jvmstat.monitor.VmIdentifier;


public class GetOwnPid {

public static void main(String[] args) {
new GetOwnPid().run();
}

public void run() {
System.out.println(getPid(this.getClass()));
}

public Integer getPid(Class<?> mainClass) {
MonitoredHost monitoredHost;
Set<Integer> activeVmPids;
try {
monitoredHost = MonitoredHost.getMonitoredHost(new HostIdentifier((String) null));
activeVmPids = monitoredHost.activeVms();
MonitoredVm mvm = null;
for (Integer vmPid : activeVmPids) {
try {
mvm = monitoredHost.getMonitoredVm(new VmIdentifier(vmPid.toString()));
String mvmMainClass = MonitoredVmUtil.mainClass(mvm, true);
if (mainClass.getName().equals(mvmMainClass)) {
return vmPid;
}
} finally {
if (mvm != null) {
mvm.detach();
}
}
}
} catch (java.net.URISyntaxException e) {
throw new InternalError(e.getMessage());
} catch (MonitorException e) {
throw new InternalError(e.getMessage());
}
return null;
}
}

 

 3, 如何获得执行进程的PID?


如果process因为未知的原因阻塞了,我们想直接kill它,如何获得该进程的pid呢?

Unix,我们可以用反射,因为UnixProcess类有pid属性

写道
if(process.getClass().getName().equals("java.lang.UNIXProcess")) {
/* 获取pid */
try {
Field f = process.getClass().getDeclaredField("pid");
f.setAccessible(true);
pid = f.getInt(p);
} catch (Throwable e) {
}
}

在这里我们可以利用它的handle属性

首先下载jna.jar

写道
if (process.getClass().getName().equals("java.lang.Win32Process") ||
process.getClass().getName().equals("java.lang.ProcessImpl")) {
/* determine the pid on windows plattforms */
try {
Field f = p.getClass().getDeclaredField("handle");
f.setAccessible(true);
long handl = f.getLong(p);

Kernel32 kernel = Kernel32.INSTANCE;
W32API.HANDLE handle = new W32API.HANDLE();
handle.setPointer(Pointer.createConstant(handl));
pid = kernel.GetProcessId(handle);
} catch (Throwable e) {
}
}

 

写道
import com.sun.jna.Native;
/* https://jna.dev.java.net/ */
public interface Kernel32 extends W32API {
Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class, DEFAULT_OPTIONS);
/* http://msdn.microsoft.com/en-us/library/ms683179(VS.85).aspx */
HANDLE GetCurrentProcess();
/* http://msdn.microsoft.com/en-us/library/ms683215.aspx */
int GetProcessId(HANDLE Process);
}

/* Copyright (c) 2007 Timothy Wall, All Rights Reserved

 *

 * This library is free software; you can redistribute it and/or

 * modify it under the terms of the GNU Lesser General Public

 * License as published by the Free Software Foundation; either

 * version 2.1 of the License, or (at your option) any later version.

 *

 * This library is distributed in the hope that it will be useful,

 * but WITHOUT ANY WARRANTY; without even the implied warranty of

 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU

 * Lesser General Public License for more details. 

 */

 

import java.util.HashMap;

import java.util.Map;

 

import com.sun.jna.FromNativeContext;

import com.sun.jna.Pointer;

import com.sun.jna.PointerType;

import com.sun.jna.win32.StdCallLibrary;

import com.sun.jna.win32.W32APIFunctionMapper;

import com.sun.jna.win32.W32APITypeMapper;

 

/** Base type for most W32 API libraries.  Provides standard options

 * for unicode/ASCII mappings.  Set the system property w32.ascii

 * to true to default to the ASCII mappings.

 */

public interface W32API extends StdCallLibrary, W32Errors {

   

    /** Standard options to use the unicode version of a w32 API. */

    Map UNICODE_OPTIONS = new HashMap() {

        {

            put(OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);

            put(OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE);

        }

    };

   

    /** Standard options to use the ASCII/MBCS version of a w32 API. */

    Map ASCII_OPTIONS = new HashMap() {

        {

            put(OPTION_TYPE_MAPPER, W32APITypeMapper.ASCII);

            put(OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.ASCII);

        }

    };

 

    Map DEFAULT_OPTIONS = Boolean.getBoolean("w32.ascii") ? ASCII_OPTIONS : UNICODE_OPTIONS;

   

    public class HANDLE extends PointerType {

         @Override

        public Object fromNative(Object nativeValue, FromNativeContext context) {

            Object o = super.fromNative(nativeValue, context);

            if (INVALID_HANDLE_VALUE.equals(o))

                return INVALID_HANDLE_VALUE;

            return o;

        }

    }

 

    /** Constant value representing an invalid HANDLE. */

    HANDLE INVALID_HANDLE_VALUE = new HANDLE() {

        { super.setPointer(Pointer.createConstant(-1)); }

        @Override

        public void setPointer(Pointer p) {

            throw new UnsupportedOperationException("Immutable reference");

        }

    };

}

/* Copyright (c) 2007 Timothy Wall, All Rights Reserved

 *

 * This library is free software; you can redistribute it and/or

 * modify it under the terms of the GNU Lesser General Public

 * License as published by the Free Software Foundation; either

 * version 2.1 of the License, or (at your option) any later version.

 *

 

 * This library is distributed in the hope that it will be useful,

 * but WITHOUT ANY WARRANTY; without even the implied warranty of

 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU

 * Lesser General Public License for more details. 

 */

 

public interface W32Errors {

        

    int NO_ERROR               = 0;

    int ERROR_INVALID_FUNCTION = 1;

    int ERROR_FILE_NOT_FOUND   = 2;

    int ERROR_PATH_NOT_FOUND   = 3;

 

}

 
还有一种方式,通过RuntimeMXBean
写道
RuntimeMXBean rtb = ManagementFactory.getRuntimeMXBean();
String processName = rtb.getName();
Integer pid = tryPattern1(processName);

private static Integer tryPattern1(String processName) {
Integer result = null;

/* tested on: */
/* - windows xp sp 2, java 1.5.0_13 */
/* - mac os x 10.4.10, java 1.5.0 */
/* - debian linux, java 1.5.0_13 */
/* all return pid@host, e.g 2204@antonius */

Pattern pattern = Pattern.compile("^([0-9]+)@.+$", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(processName);
if (matcher.matches()) {
result = new Integer(Integer.parseInt(matcher.group(1)));
}
return result;
}

相关信息还可以参照http://bugs.sun.com/view_bug.do?bug_id=4244896

 

分享到:
评论

相关推荐

    java执行可执行文件,Runtime.exec、ProcessBuilder、commons-exec

    java 执行可执行文件,Runtime.exec、ProcessBuilder、commons-exec

    Java零基础 - DOS命令del.md

    本文档介绍了如何在Java中使用ProcessBuilder类执行DOS命令。我们提供了详细的步骤说明,并附带一个简单的源码示例,演示如何使用Java代码删除文件。 内容概要 本文档涵盖以下内容: 使用Java代码执行DOS命令 使用...

    Java零基础 - ping命令.md

    本文档介绍了如何在Java中使用ProcessBuilder类执行ping命令,以检测主机的网络连通性。我们提供了详细的步骤说明,并附带一个简单的源码示例,演示如何使用Java代码执行ping命令并解析结果。 内容概要 本文档涵盖...

    Java零基础 - ipconfig命令.md

    本文档介绍了如何在Java中使用ProcessBuilder类执行DOS命令。我们提供了详细的步骤说明,并附带一个简单的源码示例,演示如何使用Java代码获取系统的网络配置信息。 内容概要 本文档涵盖以下内容: 使用Java代码...

    Java零基础(JDK13) - 常用DOS命令 - cd回到上级以及回到根.md

    本文档介绍了如何在Java中使用ProcessBuilder类执行常用的DOS命令。我们提供了详细的步骤说明,并附带一个简单的源码示例,演示如何使用cd命令回到上级目录以及回到根目录。 内容概要 本文档涵盖以下内容: 回到...

    quine:Java中使用ProcessBuilder运行时的非空查询-“计算机娱乐

    奎因使用ProcessBuilder运行时在Java中进行非空查询-“计算机娱乐:自动复制自动机”让·米洛(Jean Millo),1972年基本上是在使用ProcessBuilder充当再现代理的全新概念上制作的。 该程序输出自己的源代码,并且...

    深入研究java.lang.ProcessBuilder类.doc

    深入研究java.lang.ProcessBuilder类

    ProcessBuilder非阻塞是调用

    ProcessBuilder非阻塞是调用ProcessBuilder非阻塞是调用ProcessBuilder非阻塞是调用ProcessBuilder非阻塞是调用ProcessBuilder非阻塞是调用

    java jdk实列宝典 光盘源代码

    applications和applet,applications可以在控制台直接运行,与其他高级编程语言没有太大区别,而java的特色在于它具有编制小应用程序的功能,applet可以在internet上传输并在兼容java的web浏览器中运行的程序;...

    Java Process Utils (Forker):用于更好地控制外部进程的 Java 库-开源

    Forker Wrapper 是一个在 Java 中执行服务的“包装器”。 类似于 JSW(Java 服务包装器)和 YAJSW,但更轻量级并使用自由许可,Forker Wrapper 可用于在后台启动进程、跟踪进程 ID、捕获输出以记录日志并自动重启挂...

    java执行shell或bat脚本

    java执行shell或bat脚本,Java可以使用三种方式来执行.bat或.shell脚本文件:使用Runtime.exec()、使用ProcessBuilder、使用第三方工具包commonsexec.jar

    Java如何基于ProcessBuilder类调用外部程序

    主要介绍了Java如何基于ProcessBuilder类调用外部程序,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    java调用shell向DataX传递参数,where条件,包含特殊字符

    java调用shell向DataX传递参数,where条件,包含特殊字符。java调用shell向DataX传递参数,where条件,包含特殊字符

    Java JDK实例宝典

    7 使用ProcessBuilder执行本地命令 16. 8 泛型编程 16. 9 注释功能Annotation 16. 10 监控与管理虚拟机 16. 11 线程——Callable和Future 16. 12 线程——任务执行架构 16. 13 线程——锁...

    linux使用管道命令执行ps获取cpu与内存占用率

    主要介绍了linux使用管道命令执行ps获取cpu与内存占用率的示例,需要的朋友可以参考下

    gPROMS process builder 4.2 完整安装版 网盘链接

    这是我在国外网盘下载的,该版本是完整破解版,和Aspen plus 一样都是用于化工过程模拟及优化的软件, 用于大家学习交流,如果你要使用它用于发表论文或者商业目的,最好购买正版。 本人所在课题组有该软件正版授权,...

    08 ProcesBuilder

    个人对于java.lang.ProcessBuilder的分析

    JAVA 范例大全 光盘 资源

    实例3 在Eclipse中创建第一个Java程序 4 常见问题 javac不是内部或者外部命令 6 常见问题 找不到类文件 6 常见问题 语法错误 7 第2章 Java基础语法 9 实例4 变量和常量 9 实例5 基本数据类型转换 10 实例6 ...

    java-cmd-exec:一个简单的ProcessBuilder包装器

    java-cmd-exec 一个简单的ProcessBuilder包装器 例子 公共类Md5sumCommand扩展了Command { @Override protected File directory() { return new File&#40;"."&#41;; } @Override protected String command() { ...

    写给大忙人看的JAVA SE 8

    7.12.1 执行Shell命令 159 7.12.2 字符串插值 160 7.12.3 脚本输入 161 7.13 Nashorn和JavaFX 162 练习 164 第8章杂项改进 166 8.1 字符串 168 8.2 数字类 168 8.3 新的数学函数 169 8.4 集合 170 8.4.1 集合类中...

Global site tag (gtag.js) - Google Analytics