java 命令行执行及工具类封装【实用】

java 编程中,特别是一些工具开发过程中,经常会调用系统命令行,如 windowns 上的 CMD ,linux 操作系统上的 sh 等。

分析

java 提供了调用 CMDsh 的 API , 它被封装在 Runtime 类中。其 exec 方法示意如下:
java 命令行执行及工具类封装【实用】_第1张图片

简单使用方法如下:

	public static void main(String[] args) throws IOException {
        Runtime.getRuntime().exec("command");
	}

更多 Runtime.exec 见 java Runtime.exec方法详解

问题

简单使用 Runtime.exec 存在如下问题:

  • 线程阻塞 – Runtime.exec 线程阻塞及处理
  • 没有返回正确的输出或错误信息

为此特编写了如下工具类

工具类

日常开发中调用命令行后,需要拿到执行结果或错误结果,并且要高效,为此,结合 Java 异步编程经验,封装了如下工具类:

package com.xzbd.common.utils;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.apache.commons.lang3.SystemUtils;

public class CommandUtil {

	public static String LINUX_CMD = "/bin/sh";
	public static String WIN_CMD = "cmd.exe";
	// time out
	private static long TIME_OUT = 20;
	// time out unit
	private static TimeUnit TIME_OUT_UNIT = TimeUnit.SECONDS;

	public static void main(String[] args) throws IOException {
		String result = CommandUtil.runCmd("ls /home/", 12, TimeUnit.SECONDS);
		System.out.println(result);

	}

	public static String runCmd(String command) {
		return runCmd(command, TIME_OUT, TIME_OUT_UNIT);
	}

	public static String runCmd(String command, long time, TimeUnit unit) {
		String[] cmds = createCmd(command);
		String cmd = String.join(" ", cmds);
		System.out.println("CMD: " + cmd);
		System.out.println(SystemUtils.LINE_SEPARATOR);
		Process pro = null;
		try {
			pro = Runtime.getRuntime().exec(cmds);
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException("cmd exec error");
		}
		ExecutorService executorService = Executors.newFixedThreadPool(2);
		Future<String> result = executorService.submit(new ReaderTask(pro.getInputStream()));
		Future<String> errResult = executorService.submit(new ReaderTask(pro.getErrorStream()));
		String r1 = resultHandle(result, time, unit);
		String r2 = resultHandle(errResult, time, unit);
		executorService.shutdown();
		if (r2 != null && !r2.isBlank())
			return r2;
		return r1;
	}

	/**
	 * 创建cmd
	 */
	private static String[] createCmd(String command) {
		if (SystemUtils.IS_OS_LINUX) {
			// linux -c
			return new String[] { LINUX_CMD, "-c", command };
		} else if (SystemUtils.IS_OS_WINDOWS) {
			// win10 /c
			return new String[] { WIN_CMD, "/c", command };
		} else {
			String systemInfo = SystemUtils.OS_NAME + " " + SystemUtils.OS_ARCH + " " + SystemUtils.OS_VERSION;
			throw new RuntimeException("OS Not Supported , the current OS is :" + systemInfo);
		}
	}

	/**
	 * 预留显示效果控制,例如日志
	 */
	private static String resultHandle(Future<String> result, long time, TimeUnit unit) {
		String tmp = null;
		try {
			tmp = result.get(time, unit);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		} catch (TimeoutException e) {
			e.printStackTrace();
		}
		return tmp;
	}

	private static class ReaderTask implements Callable<String> {
		private InputStream inputStream;
		private StringBuilder queryResult;

		public ReaderTask(InputStream inputStream) {
			this.inputStream = inputStream;
			queryResult = new StringBuilder();
		}

		@Override
		public String call() throws Exception {
			BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream));
			String line = null;
			while ((line = bf.readLine()) != null) {
				queryResult.append(line).append(SystemUtils.LINE_SEPARATOR);
			}
			bf.close();
			return queryResult.toString();
		}
	}
}

其中 SystemUtils 源自 commons-lang3 ,其 mvn 依赖如下:

		
		<dependency>
			<groupId>org.apache.commonsgroupId>
			<artifactId>commons-lang3artifactId>
			<version>3.12.0version>
		dependency>

也可以自己实现一个System 工具类,见 java 获取系统信息

你可能感兴趣的:(java技术,Linux,java,Runtime,CMD)