使用ProcessBuilder创建process时,BufferedReader.readLine()超时

在Java中使用ProcessBuilder创建进程时,通过设置redirectErrorStream为true合并错误和标准输出。关闭输入流避免阻塞,并使用BufferedReader读取输出。不关闭输入流或不合并流可能导致readLine()超时或阻塞问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在Java中,用ProcessBuilder创建一个Process,向cmd输入命令,拿到正常输出和error,方法如下:
String cmds = ...;
ProcessBuilder builder = new ProcessBuilder("cmd");  
builder.redirectErrorStream(true);  //将error和正常输出都转换到输出,用getInputStream都可以得到
Process process = builder.start();  
BufferedWriter pStdin = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
pStdin.write(cmd);
pStdin.newLine();
pStdin.flush();
process.getOutputStream().close(); // 关掉输入流
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));  
String readLine = br.readLine();  
while (readLine != null) {  
   System.out.println(readLine);  //既有正常输出和error message。
   readLine = br.readLine();  
}  
如果去掉第二行标红的代码,执行时会报错,原因可能是process一直等待outputStream输入。
如果不加第一行标红代码,同事使用process.waitfor,也可能报错,原因可能是getErrorStream流和getInputStream流相互阻塞,所以最好将他们合并。
public static String exec(String cmd){ BufferedReader reader = null; BufferedReader errorBufReader = null; Process exec = null; cmds[2] = cmd; Log.e(TAG,"exec cmd is " + cmd); try { exec = Runtime.getRuntime().exec(cmds); reader = new BufferedReader(new InputStreamReader(exec.getInputStream())); errorBufReader = new BufferedReader(new InputStreamReader(exec.getErrorStream())); ExecutorService executorService = Executors.newFixedThreadPool(1); Future<StringBuilder> errorFuture = executorService.submit(new InputReaderThread(1,errorBufReader)); String temp = null; StringJoiner success = new StringJoiner("\r\n"); while ((temp = reader.readLine())!=null){ success.add(temp); } int exitVal = exec.waitFor(); if(exitVal == 0){ Log.e(TAG,"success builder"); return success.toString(); }else { StringBuilder builderError = errorFuture.get(); Log.e(TAG, " error code is "+exitVal); Log.e(TAG,"error builder is "+ builderError.toString()); return builderError.toString(); } } catch (IOException | InterruptedException | ExecutionException | IllegalThreadStateException e) { e.printStackTrace(); } finally { try { if(errorBufReader!=null)errorBufReader.close(); if(reader!=null)reader.close(); if(exec!=null)exec.destroy(); }catch (Exception e){ e.printStackTrace(); } } return null; } public static boolean output(String shellCommand) { String line = null; try { String[] cmd = new String[]{"/system/bin/sh", "-c", shellCommand}; Process exec = Runtime.getRuntime().exec(cmd); int code = exec.waitFor(); exec.destroy(); return code==0; } catch (Exception e) { e.printStackTrace(); } return false; } public static String exeCommand(String[] commands, boolean isRoot, boolean isNeedResultMsg) { int result = -1; if (commands == null || commands.length == 0) { return String.format("%s", result); } Process process = null; BufferedReader successResult = null; BufferedReader errorResult = null; StringBuilder successMsg = new StringBuilder(); DataOutputStream os = null; try { process = Runtime.getRuntime().exec(isRoot?COMMAND_SU:COMMAND_SH); os = new DataOutputStream(process.getOutputStream()); for (String command : commands) { if (command == null) { continue; } os.write(command.getBytes()); os.writeBytes(COMMAND_LINE_END); os.flush(); } os.writeBytes(COMMAND_EXIT); os.flush(); if (isNeedResultMsg) { errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream())); ExecutorService executorService = Executors.newFixedThreadPool(1); Future<StringBuilder> errorFuture = executorService.submit(new InputReaderThread(1,errorResult)); successResult = new BufferedReader(new InputStreamReader(process.getInputStream())); String s; while ((s = successResult.readLine()) != null) { successMsg.append(s); } int exitCode = process.waitFor(); if(exitCode == 0){ Log.e(TAG,"success builder"); return successMsg.toString(); }else { StringBuilder builderError = errorFuture.get(); Log.e(TAG,"error code is "+ exitCode); Log.e(TAG,"error builder is "+ builderError.toString()); return builderError.toString(); } } } catch (Exception e) { e.printStackTrace(); Log.e(TAG,"Exception: "+getStackTraceString(e)); return "NoRootPermission"; } finally { try { if (os != null) { os.close(); } if (successResult != null) { successResult.close(); } if (errorResult != null) { errorResult.close(); } } catch (IOException e) { e.printStackTrace(); } if (process != null) { process.destroy(); } } return successMsg.toString(); } public static class InputReaderThread implements Callable<StringBuilder> { private BufferedReader reader; private int type; public InputReaderThread(int type,BufferedReader inputStream) { this.reader = inputStream; this.type = type; } @Override public StringBuilder call() throws Exception { StringBuilder result = new StringBuilder(); try{ String temp = null; while (reader!=null && (temp = reader.readLine())!=null){ // Log.e(TAG,(type==1?"Error":"Success") + " temp is " + temp); result.append(String.format("%s \r\n",temp)); temp = null; } }catch (IOException e){ result = new StringBuilder("fail:" + e.getMessage()); result.append(e.getMessage()); } return result; } }优化代码
06-17
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值