如何使用Java调用Linux系统命令
作者:DreamMakers 发布时间:2021-12-24 20:45:31
Java调用Linux系统命令
有时候,我们在使用Java做一些操作时,可能性能上并不能达到我们满意的效果,就拿最近工作中的遇到的一个场景来说,需要对大量的小文件进行合并成一个大文件。
最开始的想法是使用Java做文件操作,遍历所有小文件然后往一个文件写(可以做成并发写),但是发现操作过程中遇到个问题,写一千多个小文件在本机Windows下需要花费几十秒的时间,即使在Linux环境下高配置的机器也需要将近十秒,这明显对接口的响应时间产生重要影响。这块怎么优化下呢?
我们都知道在Linux下可以进行大文件的分割和合并,分别采用split和cat命令,于是做了个实验,在Linux下对相同的一个1G文件进行切割成1000个小文件,然后对这一千多个小文件进行合并。效果是惊人的!!!竟然瞬间就能合成完成了!这更加让我坚定了应该使用系统命令进行批量小文件进行合并的想法。
我们这里封装一个类,用来调用系统命令,然后得到系统调用的返回结果。
我们先封装了一个返回结果类:
package com.majing.learning.fileupload.common.process;
public class ProcessResult {
private boolean success = false;
private String errorMessage;
private String outputMessage;
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public String getOutputMessage() {
return outputMessage;
}
public void setOutputMessage(String outputMessage) {
this.outputMessage = outputMessage;
}
}
接着我们给出封装的系统调用实现类:
package com.majing.learning.fileupload.common.process;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import org.apache.commons.lang3.StringUtils;
public class CommandUtils {
public static ProcessResult runCmdTest(ExecutorService executorService, String command) throws IOException, InterruptedException {
StringBuilder queryInputResult = new StringBuilder();
StringBuilder queryErroInputResult = new StringBuilder();
ProcessResult processResult = new ProcessResult();
String[] cmd = { "/bin/sh", "-c", command};
Process pro = Runtime.getRuntime().exec(cmd);
CountDownLatch lock = new CountDownLatch(2);
executorService.submit(new ProcessCheckTask(queryInputResult, lock, pro.getInputStream()));
executorService.submit(new ProcessCheckTask(queryErroInputResult, lock, pro.getErrorStream()));
boolean done = false;
while (!done) {
lock.await();
done = true;
}
processResult.setOutputMessage(queryInputResult.toString());
processResult.setErrorMessage(queryErroInputResult.toString());
processResult.setSuccess(StringUtils.isBlank(processResult.getErrorMessage()));
return processResult;
}
}
其中ProcessCheckTask类如下:
package com.majing.learning.fileupload.common.process;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.CountDownLatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.majing.learning.fileupload.common.ConstValues;
public class ProcessCheckTask implements Runnable {
private static Logger logger = LoggerFactory.getLogger(ProcessCheckTask.class);
/** 锁 */
private CountDownLatch lock;
/** 执行结果输入流 */
private InputStream inputStream;
/** 字符拼接 */
private StringBuilder queryInputResult;
public ProcessCheckTask(StringBuilder queryInputResult, CountDownLatch lock, InputStream inputStream) {
super();
this.lock = lock;
this.inputStream = inputStream;
this.queryInputResult = queryInputResult;
}
@Override
public void run() {
try {
BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream));
String line = null;
while ((line = bf.readLine()) != null && line.length() > 0) {
queryInputResult.append(line).append("\n");
}
} catch (Exception e) {
logger.error(ConstValues.EXCEPTION_OCCURED, e);
} finally {
lock.countDown();
}
}
}
上面是一个简单实现,但是可能会存在一个问题,那就是执行系统命令的时间如果本身比较长,如果不想一直等待到系统命令执行完,而是在一段时间没有返回就直接认为失败,所以需要增加过期时间的考虑。这里我借助于Future框架,将上面的调用系统命令的方法封装成一个Callable对象。
package com.majing.learning.fileupload.common.process;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
public class CommandTask implements Callable<ProcessResult>{
private ExecutorService executorService;
private String command;
public CommandTask(ExecutorService executorService, String command){
this.executorService = executorService;
this.command = command;
}
@Override
public ProcessResult call() throws Exception {
return CommandUtils.runCmdTest(executorService, command);
}
}
然后在上面的CommandUtils的基础上再封装一层变成CommandHelper,具体实现如下:
package com.majing.learning.fileupload.common.process;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.majing.learning.fileupload.common.ConstValues;
public class CommandHelper {
private static Logger logger = LoggerFactory.getLogger(CommandHelper.class);
private static ExecutorService executorService=Executors.newFixedThreadPool(50);
private static long default_timeout = 8000;
public static ProcessResult process(String command){
return process(command, default_timeout, TimeUnit.MILLISECONDS);
}
public static ProcessResult process(String command, long timeout, TimeUnit unit){
CommandTask commandTask = new CommandTask(executorService, command);
Future<ProcessResult> processResult = executorService.submit(commandTask);
ProcessResult result = null;
try{
result = processResult.get(timeout, unit);
}catch(Exception e){
logger.error(ConstValues.EXCEPTION_OCCURED, e);
}
return result;
}
}
至此,我们在需要调用系统命令时直接调用CommandHelper.process(command)就可以了,然后拿到返回结果ProcessResult。我也是自己做个记录,有需要的朋友可以直接拿去用。
顺便说一句,采用封装的这个类在完成上面相同的任务时,时间都在相同的机器上,耗时从原来的10s瞬间减少至200ms以内,由此可见,在适当的场景调用系统命令是多么重要啊。
java执行Linux命令,支持通配符(*)
java执行linux或者windows命令,这个需求比较常见。
但是若使用 Runtime.getRuntime().exec(cmd); 会发现,若cmd中含有通配符,则无法执行,如cp /dira/*.txt /dirb
可用如下方式执行:
String[] cmdArr = new String[3];
cmdArr[0] = "/bin/sh";
cmdArr[1] = "-c";
cmdArr[2] = command;
process = Runtime.getRuntime().exec(cmdArr);
来源:https://majing.blog.csdn.net/article/details/88773993
猜你喜欢
- 本文实例讲述了C#实现DataTable映射成Model的方法。分享给大家供大家参考,具体如下:这是数据库开发中经常遇到的问题,当然,这可以
- JavaWeb登录界面登录失败在同一页面进行提示方法使用JSP 通过提交表单方式 判断账号密码是否正确 不正确则调用req.setAttri
- 如何在Unity里修改FBX模型自带的动画我们在把模型做成预制体的时候会出现,模型当前看到的位置和动画播放的位置不一致,而且模型动画文件又是
- 问题使用前后端分离模式开发项目时,往往会遇到这样一个问题 -- 无法跨域获取服务端数据这是由于浏览器的同源策略导致的,目的是为了安全。在前后
- IO操作字节流java.io.InputStream 输入流,主要是用来读取文件内容的。java.io.OutputStream 输出流,主
- 序言:使用MyBatis3提供的注解可以逐步取代XML,例如使用@Select注解直接编写SQL完成数据查询,使用@SelectProvid
- Oracle 数据库,查询增加RowBounds限制查询条数,默认是0到1000条private final static int rowL
- MediaQuery通常情况下,不会直接将MediaQuery当作一个控件,而是使用MediaQuery.of获取当前设备的信息,用法如下:
- 业务现象代码中有一部分代码多次嵌套循环和数据处理,执行速度很慢解决方案通过多线程1、启用多线程private final static Ex
- 我们先来看看公众号发放现金红包的效果:需要调用商户平台的接口,接口发放规则如下:1.发送频率限制——默认1800/min 2.发送个数上限—
- 一、简介SpringBoot 最强大的功能就是把我们常用的场景抽取成了一个个starter(场景启动器),我们通过引入SpringBoot
- 做完一个Android项目之后,如何才能把项目发布到Internet上供别人使用呢?我们需要将自己的程序打包成Android安装包文件–AP
- fastjson转换对象实体@JsonProperty不生效项目场景请求第三方应用 返回json数据问题描述第三方返回的数据中,存在java
- 目录创建线程管理线程销毁线程创建线程线程是通过扩展 Thread 类创建的。扩展的 Thread 类调用 Start() 方法来开
- 前言应用系统需要通过Cache来缓存不经常改变得数据来提高系统性能和增加系统吞吐量,避免直接访问数据库等低速存储系统。缓存的数据通常存放在访
- 10万+IT人都在关注的图片批量压缩上传方案(完整案例+代码)背景需求:为了客户端访问图片资源时,加载图片更流畅,体验更好,通常不会直接用原
- 问题描述在使用poi-tl word模版工具时,发现生成的文档中,图片格式为嵌入型,有的图片甚至被表格遮挡一半。而自己想要的图片格式为上下型
- Spring整合Myabtis思路的分析引入相关依赖SpringMyabtismysqlMybatsi-spring…
- 用户提出一个需求:当修改产品价格的时候,需要记录操作日志,什么时候做了什么事情。想必这个案例,只要是做过应用系统的小伙伴们,都应该遇到过吧?
- 引言容器是Java基础类库中使用频率最高的一部分,Java集合包中提供了大量的容器类来帮组我们简化开发,我前面的文章中对Java集合包中的关