目录
一,问题描述
在实现一个功能时,需要将一个GitHub项目拷贝到一个新的文件夹中,并在新文件夹中执行cmd命令。
中间涉及到多次调用含有cmd命令的方法,结果在执行最后的cmd命令时,Process.waitFor()返回值为128(当返回值为0时,表示正常执行)
1,错误代码如下
GitUtil
import java.io.*;
public class GitUtil {
public static long runRollBackGitShell(String projectPath, int num) {
try {
long startTime = System.currentTimeMillis();
long endTime, usedTime;
System.out.println("开始执行命令:git reset --hard HEAD~" + num);// 注意这里必须是HEAD~1而不是HEAD^
String comm = "cmd.exe /c cd " + projectPath + "&& git reset --hard HEAD~" + num;
Process proc = Runtime.getRuntime().exec(comm);
int processCode = proc.waitFor();
System.out.println("processCode: " + processCode);
if(processCode == 0) {
System.out.println("命令执行完成");
endTime = System.currentTimeMillis();
// 获取扫描时间
usedTime = (endTime - startTime) / 1000;
System.out.println("更新commit数据用时" + usedTime + "s");
System.out.println("-----------------------------");
return usedTime;
} else {
System.out.println("Error in GitUtil[23]");
}
// proc.exitValue();
} catch (Exception e) {
e.printStackTrace();
}
return -1;
}
public static void copyFolderByCMD(String scrFolder, String desFolder) {
Runtime run = Runtime.getRuntime();
try {
Process proc = run.exec("cmd.exe /c " + "xcopy " + scrFolder + " " + desFolder + " /s /f /h");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void deleteFile(File file) {
//判断文件不为null或文件目录存在
if (file == null || !file.exists()){
return;
}
//取得这个目录下的所有子文件对象
File[] files = file.listFiles();
//遍历该目录下的文件对象
for (File f: files){
//打印文件名
String name = file.getName();
//判断子目录是否存在子目录,如果是文件则删除
if (f.isDirectory()){
deleteFile(f);
}else {
f.delete();
}
}
//删除空文件夹 for循环已经把上一层节点的目录清空。
file.delete();
}
public static void refreshWorkspaceByCMD(String path, String projectFileName) {
try {
File f = new File(path + "\\" + projectFileName + "-workspace");
deleteFile(f);// 删除该目录下所有文件夹和文件
f = new File(path + "\\" + projectFileName + "-workspace");
// 在项目所在目录下创建"项目名-workspace"文件夹
f.mkdir();
f = new File(path + "\\" + projectFileName + "-workspace" + "\\" + projectFileName);
// 在"项目名-workspace"文件夹中创建与项目同名的文件夹
if(f.mkdir()) {
String srcFolder = path + "\\" + projectFileName;
String desFolder = path + "\\" + projectFileName + "-workspace" + "\\" + projectFileName;
copyFolderByCMD(srcFolder, desFolder);
} else {
System.out.println("Error");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Main
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URLEncoder;
import java.util.*;
public class Main {
public static void main(String[] args) {
String path = "D:\\TestProjects";
String projectFileName = "untitled";
String projectPath = path + "\\" + projectFileName;// 暂时统一,避免重复输入
String newProjectPath = path + "\\" + projectFileName + "-workspace" + "\\" + projectFileName;
GitUtil.refreshWorkspaceByCMD(path, projectFileName);
GitUtil.runRollBackGitShell(newProjectPath, 2);
}
}
2,执行结果
二,解决方法
首先查了下Process.waitFor()返回值128是什么意思,@scyatcs【Process.waitFor()的返回值含义】"OS error code 128: Key has been revoked"(密钥已被吊销,不理解啥意思)
后来想到会不会是因为调用了太多个执行cmd命令的函数,然后就去搜索waitFor用法,找到了问题所在@weixin_30387663【解决waitfor()阻塞问题】
ProcessBuilder.start() 和 Runtime.exec 方法创建一个本机进程,并返回 Process 子类的一个实例,该实例可用来控制进程并获得相关信息。
Process 类提供了执行从进程输入、执行输出到进程、等待进程完成、检查进程的退出状态以及销毁(杀掉)进程的方法。
创建进程的方法可能无法针对某些本机平台上的特定进程很好地工作,比如,本机窗口进程,守护进程,Microsoft Windows 上的 Win16/DOS 进程,或者 shell 脚本。
创建的子进程没有自己的终端或控制台。它的所有标准 io(即 stdin、stdout 和 stderr)操作都将通过三个流 (getOutputStream()、getInputStream() 和 getErrorStream()) 重定向到父进程。父进程使用这些流来提供到子进程的输入和获得从子进程的输出。
因为有些本机平台仅针对标准输入和输出流提供有限的缓冲区大小,如果读写子进程的输出流或输入流迅速出现失败,则可能导致子进程阻塞,甚至产生死锁。
也就是说:如果程序不断在向标准输出流和标准错误流写数据,而JVM不读取的话,当缓冲区满之后将无法继续写入数据,最终造成阻塞在waitFor()这里。
于是在GitUtil中添加了clearStream方法
public static void clearStream(InputStream stream) {
String line = null;
try (BufferedReader in = new BufferedReader(new InputStreamReader(stream));) {
while ((line = in.readLine()) != null) {}
} catch (IOException e) {
e.printStackTrace();
}
}
并在每次执行完命令行后(run.exec),清空标准输出缓冲区和标准错误流的内容
修改后的GitUtil如下:
import java.io.*;
public class GitUtil {
public static long runRollBackGitShell(String projectPath, int num) {
try {
long startTime = System.currentTimeMillis();
long endTime, usedTime;
System.out.println("开始执行命令:git reset --hard HEAD~" + num);// 注意这里必须是HEAD~1而不是HEAD^
String comm = "cmd.exe /c cd " + projectPath + "&& git reset --hard HEAD~" + num;
Process proc = Runtime.getRuntime().exec(comm);
clearStream(proc.getInputStream());
clearStream(proc.getErrorStream());
int processCode = proc.waitFor();
System.out.println("processCode: " + processCode);
if(processCode == 0) {
System.out.println("命令执行完成");
endTime = System.currentTimeMillis();
// 获取扫描时间
usedTime = (endTime - startTime) / 1000;
System.out.println("更新commit数据用时" + usedTime + "s");
System.out.println("-----------------------------");
return usedTime;
} else {
System.out.println("Error in GitUtil[23]");
}
} catch (Exception e) {
e.printStackTrace();
}
return -1;
}
public static void copyFolderByCMD(String scrFolder, String desFolder) {
Runtime run = Runtime.getRuntime();
try {
Process proc = run.exec("cmd.exe /c " + "xcopy " + scrFolder + " " + desFolder + " /s /f /h");
clearStream(proc.getInputStream());
clearStream(proc.getErrorStream());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void deleteFile(File file) {
//判断文件不为null或文件目录存在
if (file == null || !file.exists()){
return;
}
//取得这个目录下的所有子文件对象
File[] files = file.listFiles();
//遍历该目录下的文件对象
for (File f: files){
//打印文件名
String name = file.getName();
//判断子目录是否存在子目录,如果是文件则删除
if (f.isDirectory()){
deleteFile(f);
}else {
f.delete();
}
}
//删除空文件夹 for循环已经把上一层节点的目录清空。
file.delete();
}
public static void refreshWorkspaceByCMD(String path, String projectFileName) {
try {
File f = new File(path + "\\" + projectFileName + "-workspace");
deleteFile(f);// 删除该目录下所有文件夹和文件
f = new File(path + "\\" + projectFileName + "-workspace");
// 在项目所在目录下创建"项目名-workspace"文件夹
f.mkdir();
f = new File(path + "\\" + projectFileName + "-workspace" + "\\" + projectFileName);
// 在"项目名-workspace"文件夹中创建与项目同名的文件夹
if(f.mkdir()) {
String srcFolder = path + "\\" + projectFileName;
String desFolder = path + "\\" + projectFileName + "-workspace" + "\\" + projectFileName;
copyFolderByCMD(srcFolder, desFolder);
} else {
System.out.println("Error");
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void clearStream(InputStream stream) {
String line = null;
try (BufferedReader in = new BufferedReader(new InputStreamReader(stream));) {
while ((line = in.readLine()) != null) {}
} catch (IOException e) {
e.printStackTrace();
}
}
}
o(* ̄▽ ̄*)ブNice