java中process方法用处_在java应用中如何用Process和ProcessBuilder 执行命令?

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

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

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

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

Java代码 ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg1", "myArg2");

Map 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 command = new ArrayList();

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专门描述了这个问题

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

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

或许我们可以使用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 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;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值