`
lzhnightwind
  • 浏览: 23552 次
  • 性别: 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执行js导致命令执行1

    在Java中,我们可以使用ScriptEngineManager来执行JS代码。ScriptEngineManager是一个javax.script包中的类,提供了执行脚本的能力。我们可以使用它来执行JS代码,并将其作为一个攻击载荷。 在执行JS代码时,我们...

    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调用应用程序.pdf

    在本文中,我们将探讨使用 Java 调用应用程序的方法和技术。Java 是一种广泛使用的编程语言,具有强大的功能和灵活性,广泛应用于web开发、安卓应用开发、桌面应用开发等领域。通过 Java,我们可以调用各种应用程序...

    Java零基础 - ipconfig命令.md

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

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

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

    ShellUtils.java,Android adb shell执行类

    一个用于在Android开发中 执行adb shell命令的类,可以以最高权限(su)执行。例如mount命令等

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

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

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

    深入研究java.lang.ProcessBuilder类

    ProcessBuilder非阻塞是调用

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

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

    主要介绍了Java如何基于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

    Struts2 S2-029远程代码执行漏洞初探1

    在 Struts2 中,标签库使用 OGNL 表达式来获取对象数据,例如 `&lt;s:property value="#parameters.msg" /&gt;`,Struts2 会解析 value 中的值,并当作 OGNL 表达式进行执行,获取到 parameters 对象的 msg 属性。...

    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 线程——锁...

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

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

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

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

Global site tag (gtag.js) - Google Analytics