如何使用Java調(diào)用Linux系統(tǒng)命令
Java調(diào)用Linux系統(tǒng)命令
有時候,我們在使用Java做一些操作時,可能性能上并不能達(dá)到我們滿意的效果,就拿最近工作中的遇到的一個場景來說,需要對大量的小文件進(jìn)行合并成一個大文件。
最開始的想法是使用Java做文件操作,遍歷所有小文件然后往一個文件寫(可以做成并發(fā)寫),但是發(fā)現(xiàn)操作過程中遇到個問題,寫一千多個小文件在本機Windows下需要花費幾十秒的時間,即使在Linux環(huán)境下高配置的機器也需要將近十秒,這明顯對接口的響應(yīng)時間產(chǎn)生重要影響。這塊怎么優(yōu)化下呢?
我們都知道在Linux下可以進(jìn)行大文件的分割和合并,分別采用split和cat命令,于是做了個實驗,在Linux下對相同的一個1G文件進(jìn)行切割成1000個小文件,然后對這一千多個小文件進(jìn)行合并。效果是驚人的?。?!竟然瞬間就能合成完成了!這更加讓我堅定了應(yīng)該使用系統(tǒng)命令進(jìn)行批量小文件進(jìn)行合并的想法。
我們這里封裝一個類,用來調(diào)用系統(tǒng)命令,然后得到系統(tǒng)調(diào)用的返回結(jié)果。
我們先封裝了一個返回結(jié)果類:
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;
}
}
接著我們給出封裝的系統(tǒng)調(diào)用實現(xiàn)類:
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;
/** 執(zhí)行結(jié)果輸入流 */
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();
}
}
}
上面是一個簡單實現(xiàn),但是可能會存在一個問題,那就是執(zhí)行系統(tǒng)命令的時間如果本身比較長,如果不想一直等待到系統(tǒng)命令執(zhí)行完,而是在一段時間沒有返回就直接認(rèn)為失敗,所以需要增加過期時間的考慮。這里我借助于Future框架,將上面的調(diào)用系統(tǒng)命令的方法封裝成一個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的基礎(chǔ)上再封裝一層變成CommandHelper,具體實現(xiàn)如下:
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;
}
}
至此,我們在需要調(diào)用系統(tǒng)命令時直接調(diào)用CommandHelper.process(command)就可以了,然后拿到返回結(jié)果ProcessResult。我也是自己做個記錄,有需要的朋友可以直接拿去用。
順便說一句,采用封裝的這個類在完成上面相同的任務(wù)時,時間都在相同的機器上,耗時從原來的10s瞬間減少至200ms以內(nèi),由此可見,在適當(dāng)?shù)膱鼍罢{(diào)用系統(tǒng)命令是多么重要啊。
java執(zhí)行Linux命令,支持通配符(*)
java執(zhí)行l(wèi)inux或者windows命令,這個需求比較常見。
但是若使用 Runtime.getRuntime().exec(cmd); 會發(fā)現(xiàn),若cmd中含有通配符,則無法執(zhí)行,如cp /dira/*.txt /dirb
可用如下方式執(zhí)行:
String[] cmdArr = new String[3];
cmdArr[0] = "/bin/sh";
cmdArr[1] = "-c";
cmdArr[2] = command;
process = Runtime.getRuntime().exec(cmdArr);
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot+docker環(huán)境變量配置詳解
這篇文章主要介紹了SpringBoot+docker環(huán)境變量配置詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10
java實現(xiàn)上傳圖片尺寸修改和質(zhì)量壓縮
這篇文章主要為大家詳細(xì)介紹了java實現(xiàn)上傳圖片尺寸修改和質(zhì)量壓縮,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-04-04
SpringBoot+WebMagic實現(xiàn)網(wǎng)頁爬蟲的示例代碼
本文是對spring?boot+WebMagic+MyBatis做了整合,使用WebMagic爬取數(shù)據(jù),然后通過MyBatis持久化爬取的數(shù)據(jù)到mysql數(shù)據(jù)庫,具有一定的參考價值,感興趣的可以了解一下2023-10-10
Eclipse項目怎么導(dǎo)入IDEA并運行(超詳細(xì))
這篇文章主要介紹了Eclipse項目怎么導(dǎo)入IDEA并運行(超詳細(xì)),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10
springboot druid mybatis多數(shù)據(jù)源配置方式
這篇文章主要介紹了springboot druid mybatis多數(shù)據(jù)源配置方式,具有很好的參考價值,希望對大家有所幫助,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12

