Part1
Java可以通过Runtime来调用其他进程,如cmd命令,shell文件的执行等。可以应该该类设置系统时间,执行shell文件。此处记录几个有用应用如下。
设置本地时间
可以调用cmd /c date命令,完成本地时间设置,不过这个命令在win7下可以使用,但是win10需要管理员权限,可能无法设置系统时间。win7下使用Java实现修改本地时间代码如下,需要注意的是waitFor是必须的,否则无法立即生效。
此处注意的是,读取流信息的时候,有可能流对象太大,
不能一次性读完,导致获取的字符串顺序错乱或缺失的问题,
所以我们等程序执行完毕之后再去读取
waitFor会让线程阻塞,直至process执行完毕
/**
* 设置本地日期
* @param date yyyy-MM-dd格式
*/
private static void setSystemDate(String date){
Process process = null;
String command1 = "cmd /c date "+date;
System.out.println(command1);
try {
process = Runtime.getRuntime().exec(command1);
//必须等待该进程结束,否则时间设置就无法生效
process.waitFor();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}finally{
if(process!=null){
process.destroy();
}
}
}
网卡吞吐量计算
可以通过cat /proc/net/dev命令获取网卡信息,两次获取网卡发送和接收数据包的信息,来计算网卡吞吐量。实现如下:
/**
* @Purpose:采集网络带宽使用量
* @param args
* @return float,网络带宽已使用量
*/
public static Double getNetworkThoughput() {
Double curRate = 0.0;
Runtime r = Runtime.getRuntime();
// 第一次采集流量数据
long startTime = System.currentTimeMillis();
long total1 = calculateThoughout(r);
// 休眠1秒后,再次收集
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 第二次采集流量数据
long endTime = System.currentTimeMillis();
long total2 = calculateThoughout(r);
// 计算该段时间内的吞吐量:单位为Mbps(million bit per second)
double interval = (endTime-startTime)/1000;
curRate = (total2-total1)*8/1000000*interval;
System.out.println("收集网络带宽使用率结束,当前设备的网卡吞吐量为:"+(curRate)+"Mbps.");
return curRate;
}
/**
* 计算某个时刻网卡的收发数据总量
* @param runtime
* @return
*/
private static long calculateThoughout(Runtime runtime){
Process process = null;
String command = "cat /proc/net/dev";
BufferedReader reader = null;
String line = null;
long total = 0;
try {
process = runtime.exec(command);
reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((line = reader.readLine()) != null) {
line = line.trim();
// 考虑多网卡的情况
if (line.startsWith("eth")) {
log.debug(line);
line = line.substring(5).trim();
String[] temp = line.split("\\s+");
total+=(Long.parseLong(temp[0].trim()));// Receive
total+=(Long.parseLong(temp[8].trim()));// Transmit
}
}
} catch (NumberFormatException | IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (process != null) {
process.destroy();
}
}
return total;
}
Part2
原文链接:Java中Process类的使用与注意事项_Kevin.Yang的博客-CSDN博客_process类使用
在项目开发中,经常会遇到调用其它程序功能的业务需求,在java中通常有两种实现方法
Runtime runtime = Runtime.getRuntime();
Process p = runtime.exec(cmd);
Process process = Runtime.getRuntime().exec(new String[]{"cmd.exe", "/c", "xxxx"});
Process p=new ProcessBuilder(cmd).start();
在这里就需要认识一下process类:process是一个抽象的类,它包含6个抽象的方法
abstract public OutputStream getOutputStream();
abstract public InputStream getInputStream();
abstract public InputStream getErrorStream();
abstract public int waitFor() throws InterruptedException;
abstract public int exitValue();
abstract public void destroy();
process类提供获取子进程的输入流、子进程的输出流、子进程的错误流、等待进程完成、检查进程的推出状态以及销毁进程的方法;在这里需要提及的是创建的子进程没有自己的控制台或终端,其所有的io操作都是通过(输入流、输出流、错误流)重定向到父进程中。
来说说今天业务需求[waitfor()]:我需要在linux下首先将一个文件copy到指定的文件夹下面,之后需要将该文件夹下面的文件加入指定的jar中,那么问题就来了,必须保证其先后顺序,也就书说再执行第二个命令的时候第一个命令必须完成。
public void cmd(String cmd){
try {
Process ps= Runtime.getRuntime().exec(cmd);
} catch (Exception e) {
logger.info(e.getMessage(),e);
}
}
main函数如下:
public static void main(String[] args){
String copy="cp -rf "+source+" "+target;
String jar="jar -uvf "+jar+" "+file;
cmd(copy);
cmd(jar);
}
但是结果是新生成的jar中压根没有新加入的文件,但是文件确实copy到了指定的文件夹中,也就是谁两个命令都执行了,问题的关键就是“异步”,这时候需要waitFor()的介入
public void cmd(String cmd){
try {
Process ps= Runtime.getRuntime().exec(cmd);
ps.waitFor();
} catch (Exception e) {
logger.info(e.getMessage(),e);
}
}
那么问题就解决了!
这位作者
前不久遇到一个奇怪的问题就是ajax调用没有返回值,我在service中实现了process的调用。
String[] commands = { commandGenerate,commandPublish};
PrintWriter printWriter = response.getWriter();
for (String comm : commands) {
Runtime runtime = Runtime.getRuntime();
try {
logger.info("command is :{}",comm);
Process process = runtime.exec(comm, null, null);
BufferedInputStream inputStream = new BufferedInputStream(
process.getInputStream());
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(inputStream));
String line;
while (bufferedReader.read() != -1) {
line = bufferedReader.readLine();
System.out.println(line);
}
bufferedReader.close();
inputStream.close();
printWriter.println("success");
} catch (IOException e) {
logger.error(e.getMessage(), e);
printWriter.println(e.getMessage());
}
}
printWriter.flush();
printWriter.close();
对应的controller为:
State state = new State();
String message="";
try {
message = missionService.syntax(taskName, response);
} catch (InterruptedException e) {
e.printStackTrace();
}
state.setSuccess(true);
state.setMessage(message.trim());
return state;
打印state.getMessage()确实可以获得值,但是state返回就是空,刚开始以为是ajax的timeout时间的问题:修改了ajax的timeout时间仍然不行;将message直接赋值,然thread等待20s,结果是可以返回的,所以问题最终定为于service的这段实现。
原因分析:在上面提及了,process创建的子进程没有自己的控制台或终端,其所有的io操作都是通过(输入流、输出流、错误流)重定向到父进程中,如果该可执行程序的输入、输出或者错误输出比较多的话,而由于运行窗口的标准输入、输出等缓冲区有大小的限制,则可能导致子进程阻塞,甚至产生死锁,其解决方法就是在waitfor()方法之前读出窗口的标准输出、输出、错误缓冲区中的内容。
for (String comm : commands) {
logger.info("the comm time is:"+new Date().getTime()+" the comm is:"+comm);
Runtime runtime = Runtime.getRuntime();
Process p=null;
try {
p = runtime.exec(comm ,null,null);
final InputStream is1 = p.getInputStream();
final InputStream is2 = p.getErrorStream();
new Thread() {
public void run() {
BufferedReader br1 = new BufferedReader(new InputStreamReader(is1));
try {
String line1 = null;
while ((line1 = br1.readLine()) != null) {
if (line1 != null){
logger.info("p.getInputStream:"+line1);
if(line1.indexOf("syntax check result:")!=-1){
builder.append(line1);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
finally{
try {
is1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread() {
public void run() {
BufferedReader br2 = new BufferedReader(new InputStreamReader(is2));
try {
String line2 = null ;
while ((line2 = br2.readLine()) != null ) {
if (line2 != null){
}
}
} catch (IOException e) {
e.printStackTrace();
}
finally{
try {
is2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
p.waitFor();
p.destroy();
} catch (Exception e) {
try{
p.getErrorStream().close();
p.getInputStream().close();
p.getOutputStream().close();
}
catch(Exception ee){}
}
}
Part3
读取控制台IO流
public class App {
public static void main(String...args)throws Exception{
//执行指令
Process process = Runtime.getRuntime().exec("adb devices");
System.out.println("【控制台执行信息】");
System.out.println(readInputstream(process.getInputStream()));
System.out.println("【控制台错误信息】");
System.out.println(readInputstream(process.getErrorStream()));
}
/**
* 读取控制台打印的文字
* @param in
* @return
* @throws Exception
*/
public static String readInputstream(InputStream in) throws Exception{
InputStream inputStream = in;
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
StringBuilder sb = new StringBuilder();
String line = null;
while((line=bufferedReader.readLine())!=null){
sb.append(line).append("\n");
}
return sb.toString();
}
}
编写指令词典
package com.zeemoo.nox.actuator.consts;
import lombok.Getter;
/**
* 夜神模拟器的adb指令词典
*
* @author zhang.shushan
* @date 2018/6/8
*/
@Getter
public class NoxCmdDict {
/**
* adb脚本指令
*/
public final static String ADB = "adb";
/**
* 选择模拟器
*/
public final static String SERVER_HOST = "-s";
/**
* 模拟器列表
*/
public final static String DEVICES = "devices";
/**
* 安装apk
*/
public final static String INSTALL = "install";
/**
* 从电脑发送文件到模拟器,没什么卵用,还有权限限制
*/
@Deprecated
public final static String PUSH = "push";
/**
* 从模拟器拉取文件到电脑,没什么卵用,还有权限限制
*/
@Deprecated
public final static String PULL = "pull";
/**
* 卸载app
*/
public final static String UNINSTALL = "uninstall";
/**
* shell脚本指令,安卓内核为linux
*/
public final static String SHELL = "shell";
/**
* 列举进程
*/
public final static String SHELL_PS = "ps";
/**
* 包含某个字符串的进程信息
*/
public final static String SHELL_PS_MTH_FIND_STR ="|findStr";
/**
* 包指令
*/
public final static String SHELL_PM = "pm";
/**
* 包指令下的列举指令
*/
public final static String SHELL_PM_LIST = "list";
/**
* 包指令下的列举指令选项,表示列举所有的包名
*/
public final static String SHELL_PM_LIST_PACKAGES = "packages";
/**
* 包指令下的列举指令选项的附加选项,表示列举所有的包名和对应的路径
*/
public final static String SHELL_PM_LIST_PACKAGES_OP_NAME_AND_PATH = "-f";
/**
* 获取某个应用的路径,需要填写包名
*/
public final static String SHELL_PM_PATH = "path";
/**
* 清除应用缓存,后面接包名
*/
public final static String SHELL_PM_CLEAR_TEMP = "clear";
/**
* 应用管理指令(Activity Manager),启动或关闭应用
*/
public final static String SHELL_AM = "am";
/**
* 启动应用,最后接上包名+“/”+Activity类名
*/
public final static String SHELL_AM_START = "start";
/**
* 这个选项表示如果应用启动了就直接打开后台进程,如果没启动则启动。
* 不加此选项每次调用start的时候则每次都重启应用
*/
public final static String SHELL_AM_START_OP_XSTART = "-n";
/**
* 关闭应用,后接包名
*/
public final static String SHELL_AM_STOP = "force-stop";
/**
* 杀死进程,后接包名,似乎没什么用
*/
public final static String SHELL_AM_KILL = "kill";
/**
* 杀死后台所有进程,似乎没什么用
*/
public final static String SHELL_AM_KILL_ALL = "kill-all";
/**
* shell模拟输入
*/
public final static String SHELL_INPUT = "input";
/**
* 模拟输入文字(不支持中文)
*/
public final static String SHELL_INPUT_TEXT = "text";
/**
* 模拟点击按键
*/
public final static String SHELL_INPUT_KEYEVENT = "keyevent";
/**
* 模拟鼠标点击,后面接X,Y
*/
public final static String SHELL_INPUT_TAP = "tap";
/**
* 模拟鼠标滑动,后面接X1,Y1,X2,Y2
*/
public final static String SHELL_INPUT_SWIPE = "swipe";
/**
* 截屏
*/
public final static String SHELL_SCREEN_CAP = "screencap";
/**
* 截屏选项,后接截屏文件输出目标
*/
public final static String SHELL_SCREEN_CAP_OP_DEST = "-p";
/**
* 退出shell
*/
public final static String SHELL_EXIT = "exit";
/**
* 夜神模拟器的adb
*/
public final static String NOX_ADB = "nox_adb";
/**
* 夜神模拟器属性设置
*/
public final static String NOX_ADB_SHELL_SET_PROP = "setprop";
/**
* 设置手机的纬度
*/
public final static String NOX_ADB_SHELL_SET_PROP_LATITUDE = "persist.nox.gps.latitude";
/**
* 设置模拟器的经度
*/
public final static String NOX_ADB_SHELL_SET_PROP_LONGITUDE = "persist.nox.gps.longitude";
/**
* 设置模拟器的mac地址
*/
public final static String NOX_ADB_SHELL_SET_PROP_MAC = "setprop persist.nox.wifimac";
}
作者:zee_moo
链接:https://www.imooc.com/article/39924
来源:慕课网
本文原创发布于慕课网 ,转载请注明出处,谢谢合作
创建一个Builder类
package com.zeemoo.nox.actuator.service;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
//此处使用静态引入指令词典,可以试着删去这一行,看看有什么区别
import static com.zeemoo.nox.actuator.consts.NoxCmdDict.*;
/**
* 功能指令构建
*
* @author zhang.shushan
* @date 2018/6/8
*/
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class NoxCmdBuilder {
/**
* 夜神模拟器的根目录
*/
private String noxPath;
/**
* 给指令添加指定模拟器
* @param cmds
* @param host
* @return
*/
public List<String> addHost(List<String> cmds,String host){
if(host!=null&&"".equals(host)){
cmds.add(1, SERVER_HOST);
cmds.add(2,host);
}
return cmds;
}
/**
* 筛选字符进程
* @param example
* @return
*/
public List<String> listProcess(String example){
List<String> cmds=listPackageName();
cmds.add(SHELL_PS_MTH_FIND_STR);
cmds.add(example);
return cmds;
}
/**
* 列举所有的进程
* @return
*/
public List<String> listProcess(){
List<String> cmds = this.shellModal();
cmds.add(SHELL_PS);
return cmds;
}
/**
* 列举所有模拟器
* @return
*/
public List<String> devices(){
List<String> cmds = new ArrayList<>();
cmds.add(noxPath+File.separator+ NOX_ADB);
cmds.add(DEVICES);
return cmds;
}
/**
* 启动夜神模拟器
* @return
*/
public String startNox(){
return noxPath+File.separator+"nox.exe";
}
/**
* 截屏
* @param vitualBoxFilePath
* @return
*/
public List<String> screenCap(String vitualBoxFilePath){
List<String> cmds = new ArrayList<>();
cmds.add(SHELL_SCREEN_CAP);
cmds.add(SHELL_SCREEN_CAP_OP_DEST);
cmds.add(vitualBoxFilePath);
return cmds;
}
/**
* 模拟滑动屏幕
* @param x1
* @param y1
* @param x2
* @param y2
* @return
*/
public List<String> swipe(int x1,int y1,int x2,int y2){
List<String> cmds = this.inputModal();
cmds.add(SHELL_INPUT_SWIPE);
cmds.add(String.valueOf(x1));
cmds.add(String.valueOf(y1));
cmds.add(String.valueOf(x2));
cmds.add(String.valueOf(y2));
return cmds;
}
/**
* 模拟点击
* @param x
* @param y
* @return
*/
public List<String> click(int x,int y){
List<String> cmds = this.inputModal();
cmds.add(SHELL_INPUT_TAP);
cmds.add(String.valueOf(x));
cmds.add(String.valueOf(y));
return cmds;
}
/**
* 模拟按键
* @param keys 按键
* @return
*/
public List<String> pressKey(List<String> keys){
List<String> cmds = this.inputModal();
cmds.add(SHELL_INPUT_KEYEVENT);
cmds.addAll(keys);
return cmds;
}
/**
* 文本输入,不支持中文
* @param text
* @return
*/
public List<String> inputText(String text){
List<String> cmds = this.inputModal();
cmds.add(SHELL_INPUT_TEXT);
cmds.add(text);
return cmds;
}
/**
* 输入模式
* @return
*/
private List<String> inputModal() {
List<String> cmds = this.shellModal();
cmds.add(SHELL_INPUT);
return cmds;
}
/**
* 杀死后台所有进程
* @return
*/
public List<String> killAllAppProcess(){
List<String> cmds = this.activityManager();
cmds.add(SHELL_AM_KILL_ALL);
return cmds;
}
/**
* 杀死某个后台进程
* @param pkgNm
* @return
*/
public List<String> killAppProcess(String pkgNm){
List<String> cmds = this.activityManager();
cmds.add(SHELL_AM_KILL);
cmds.add(pkgNm);
return cmds;
}
/**
* 停止app
* @param pkgName
* @return
*/
public List<String> stopApp(String pkgName){
List<String> cmds = this.activityManager();
cmds.add(SHELL_AM_STOP);
cmds.add(pkgName);
return cmds;
}
/**
* 启动app
* @param pkgName
* @param activity
* @return
*/
public List<String> startApp(String pkgName,String activity){
List<String> cmds = this.activityManager();
cmds.add(SHELL_AM_START);
cmds.add(SHELL_AM_START_OP_XSTART);
cmds.add(pkgName+"/"+activity);
return cmds;
}
/**
* 获取某个应用的路径
* @param pkgName
* @return
*/
public List<String> getAppPath(String pkgName){
List<String> cmds = this.packageManager();
cmds.add(SHELL_PM_PATH);
cmds.add(pkgName);
return cmds;
}
/**
*
* @return
*/
public List<String> listPackageNameAndPath(){
List<String> cmds = this.listPackageName();
cmds.add(SHELL_PM_LIST_PACKAGES_OP_NAME_AND_PATH);
return cmds;
}
/**
* 列举所有的包名
* @return
*/
public List<String> listPackageName(){
List<String> cmds=this.packageManager();
cmds.add(SHELL_PM_LIST);
cmds.add(SHELL_PM_LIST_PACKAGES);
return cmds;
}
/**
* 包操作指令
* @return
*/
private List<String> packageManager(){
List<String> cmds = this.shellModal();
cmds.add(SHELL_PM);
return cmds;
}
/**
* activityManager模式
* @return
*/
private List<String> activityManager(){
List<String> cmds = this.shellModal();
cmds.add(SHELL_AM);
return cmds;
}
/**
* 从模拟器拉取文件到电脑,有权限限制
* @param virtualBoxFilePath
* @param pcFilePath
* @return
*/
@Deprecated
public List<String> pull(String virtualBoxFilePath,String pcFilePath){
List<String> cmds = new ArrayList<>();
cmds.add(noxPath+File.separator+virtualBoxFilePath);
cmds.add(PULL);
cmds.add(virtualBoxFilePath);
cmds.add(pcFilePath);
return cmds;
}
/**
* 推送文件到模拟器,有权限限制
* @param pcFilePath
* @param vitualBoxFilePath
* @return
*/
@Deprecated
public List<String> push(String pcFilePath,String vitualBoxFilePath){
List<String> cmds = new ArrayList<>();
cmds.add(noxPath+ File.separator+ NOX_ADB);
cmds.add(PUSH);
cmds.add(pcFilePath);
cmds.add(vitualBoxFilePath);
return cmds;
}
/**
* 卸载app
* @param packageName
* @return
*/
public List<String> uninstall(String packageName){
List<String> cmds = new ArrayList<>();
cmds.add(noxPath+ File.separator+ NOX_ADB);
cmds.add(UNINSTALL);
cmds.add(packageName);
return cmds;
}
/**
* 安装app
* @param apkPath
* @return
*/
public List<String> install(String apkPath){
List<String> cmds = new ArrayList<>();
cmds.add(noxPath+ File.separator+ NOX_ADB);
cmds.add(INSTALL);
cmds.add(apkPath);
return cmds;
}
/**
* 设置mac地址
* @param mac
* @return
*/
public List<String> setMac(String mac){
List<String> cmds = this.shellModal();
cmds.add(NOX_ADB_SHELL_SET_PROP);
cmds.add(NOX_ADB_SHELL_SET_PROP_MAC);
cmds.add(mac);
return cmds;
}
/**
* 设置经度
* @param longitude
* @return
*/
public List<String> setLongitude(Double longitude){
List<String> cmds = this.shellModal();
cmds.add(NOX_ADB_SHELL_SET_PROP);
cmds.add(NOX_ADB_SHELL_SET_PROP_LONGITUDE);
cmds.add(longitude.toString());
return cmds;
}
/**
* 设置模拟器纬度
* @param latitude
* @return
*/
public List<String> setLatitude(Double latitude){
List<String> cmds = this.shellModal();
cmds.add(NOX_ADB_SHELL_SET_PROP);
cmds.add(NOX_ADB_SHELL_SET_PROP_LATITUDE);
cmds.add(latitude.toString());
return cmds;
}
/**
* shell模式,设置模拟器属性之类的
* @return
*/
private List<String> shellModal(){
List<String> cmds = new ArrayList<>();
cmds.add(noxPath+ File.separator+ NOX_ADB);
cmds.add(SHELL);
return cmds;
}
/**
* shell模式,清除缓存
* @return
*/
public List<String> clearTemp(String pckName) {
List<String> cmds = this.shellModal();
cmds.add(SHELL_PM_CLEAR_TEMP);
cmds.add(pckName);
return cmds;
}
}
作者:zee_moo
链接:https://www.imooc.com/article/39924
来源:慕课网
本文原创发布于慕课网 ,转载请注明出处,谢谢合作
测试
public static void main(String...args)throws Exception{
NoxCmdBuilder noxCmdBuilder = new NoxCmdBuilder("C:\\Program Files\\Nox\\bin");
System.out.println(noxCmdBuilder.listPackageName());
}
输出结果:
[C:\Program Files\Nox\bin\nox_adb, shell, pm, list, packages]
直接将这个list放入ProcessBuilder中使用,就可以获得所有的包名了。我们来试一下。修改main如下
public static void main(String... args) throws Exception {
NoxCmdBuilder noxCmdBuilder = new NoxCmdBuilder("C:\\Program Files\\Nox\\bin");
Process start = new ProcessBuilder().command(noxCmdBuilder.listPackageName()).start();
//此处注意的是,读取流信息的时候,有可能流对象太大,
//不能一次性读完,导致获取的字符串顺序错乱或缺失的问题,
//所以我们等程序执行完毕之后再去读取
//waitFor会让线程阻塞,直至process执行完毕
start.waitFor();
System.out.println(readInputstream(start.getInputStream()));
}