Java中通过Runtime启动带Scanner.nextLine输入的class时无法输入如何解决
问题根因
- 通过
Runtime.exec启动的子进程拥有独立的标准输入/输出/错误流,默认不会和父进程的控制台绑定,父进程控制台输入的内容无法直接传递给子进程的System.in - 现有代码的执行逻辑是先同步读取子进程的标准输出,但子进程此时卡在
Scanner.nextLine()等待输入,没有输出内容生成,导致父子进程死锁:父进程等子进程输出,子进程等父进程传入输入
修复方案
核心修改点
- 通过
Process.getOutputStream()获取子进程标准输入对应的输出流,往这个流写入的内容会直接传入子进程的System.in - 开独立线程分别读取子进程的标准输出和错误输出,避免流缓冲区满导致子进程阻塞
- 写入输入内容时必须补充换行符并手动刷新缓冲区,匹配
Scanner.nextLine()的读取结束规则
修复后完整代码
import java.io.*; import java.util.Scanner; public class RunExternalApp { //Run App from Path public static void runApp(String path) throws IOException, InterruptedException { Runtime runTime = Runtime.getRuntime(); Process process = runTime.exec(path); // 单独线程处理子进程标准输出 Thread outputThread = new Thread(() -> { try (InputStream inputStream = process.getInputStream(); InputStreamReader isr = new InputStreamReader(inputStream)) { int n1; char[] c1 = new char[1024]; StringBuffer standardOutput = new StringBuffer(); while ((n1 = isr.read(c1)) > 0) { standardOutput.append(c1, 0, n1); } System.out.println("Standard Output: " + standardOutput.toString()); } catch (IOException e) { e.printStackTrace(); } }); // 单独线程处理子进程错误输出,避免缓冲区满阻塞进程 Thread errorThread = new Thread(() -> { try (InputStream errorStream = process.getErrorStream(); InputStreamReader esr = new InputStreamReader(errorStream)) { int n2; char[] c2 = new char[1024]; StringBuffer errorOutput = new StringBuffer(); while ((n2 = esr.read(c2)) > 0) { errorOutput.append(c2, 0, n2); } System.out.println("Error Output: " + errorOutput.toString()); } catch (IOException e) { e.printStackTrace(); } }); outputThread.start(); errorThread.start(); // 向子进程传入输入,二选一即可 // 方案1:自动传入固定内容,无需手动输入 try (OutputStream os = process.getOutputStream(); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os))) { bw.write("测试输入内容"); bw.newLine(); // 必须加,匹配Scanner.nextLine()的换行结束规则 bw.flush(); // 必须加,确保内容写入管道而非留在缓冲区 } // 方案2:转发父进程控制台输入到子进程,需要手动在控制台输入内容 /* try (OutputStream os = process.getOutputStream(); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os)); Scanner parentScanner = new Scanner(System.in)) { String input = parentScanner.nextLine(); bw.write(input); bw.newLine(); bw.flush(); } */ // 等待子进程执行结束、流处理完成 process.waitFor(); outputThread.join(); errorThread.join(); } //Main Method public static void main(String[] args) throws IOException, InterruptedException { String path = "java -classpath E:\\code\\java\\ctppmhw\\bin\\ App"; runApp(path); } }
内容的提问来源于stack exchange,提问作者titcoi
相关产品推荐
相关产品推荐

