如何从Java程序调用带输入输出重定向的C可执行程序mylexer?
在Java中调用外部可执行文件mylexer并处理输入输出的正确方式
你当前的代码里用了<和>这种shell重定向符号,但ProcessBuilder并不会解析这些符号——它只会把每个元素当作命令的独立参数,所以mylexer会把<、path、>、output.txt都当成普通的命令行参数,而不是用来重定向输入输出的指令,这肯定达不到你想要的效果。另外还要注意路径问题:你的mylexer在Project/Lexer目录下,而Java代码在Project/Parser里,直接写"mylexer"可能会找不到这个可执行文件,需要用相对路径(比如../Lexer/mylexer)或者绝对路径来指定。
下面给你两种可行的解决方案:
方案一:直接通过Java处理输入输出(推荐,无需中间文件)
这种方式不需要生成output.txt,直接把文件内容传给mylexer的标准输入,然后读取它的标准输出,更灵活也避免了额外的文件IO开销。
public static String getTokensFromFile(String path) { StringBuilder result = new StringBuilder(); // 根据项目结构指定mylexer的相对路径 String lexerPath = "../Lexer/mylexer"; try { ProcessBuilder pb = new ProcessBuilder(lexerPath); Process process = pb.start(); // 向mylexer的标准输入写入目标文件内容 try (OutputStream os = process.getOutputStream(); FileInputStream fis = new FileInputStream(path)) { byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = fis.read(buffer)) != -1) { os.write(buffer, 0, bytesRead); } os.flush(); os.close(); // 关闭输入,告知mylexer输入结束 } // 读取mylexer输出的结果 try (InputStream is = process.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { String line; while ((line = reader.readLine()) != null) { result.append(line).append(System.lineSeparator()); } } // 等待mylexer执行完成,检查退出码判断是否执行成功 int exitCode = process.waitFor(); if (exitCode != 0) { // 读取错误流排查问题 try (InputStream err = process.getErrorStream(); BufferedReader errReader = new BufferedReader(new InputStreamReader(err))) { StringBuilder errorMsg = new StringBuilder(); String line; while ((line = errReader.readLine()) != null) { errorMsg.append(line).append(System.lineSeparator()); } throw new RuntimeException("mylexer执行失败,退出码:" + exitCode + ",错误信息:" + errorMsg); } } } catch (IOException | InterruptedException e) { e.printStackTrace(); throw new RuntimeException("调用mylexer时发生错误", e); } return result.toString().trim(); }
方案二:通过shell执行重定向(适合依赖shell特性的场景)
如果你一定要用<和>的重定向逻辑,可以让ProcessBuilder调用系统shell,把整个命令作为参数传递给shell执行,注意区分系统类型:
类Unix系统(Linux/macOS)
public static String getTokensFromFile(String path) { StringBuilder result = new StringBuilder(); String lexerPath = "../Lexer/mylexer"; String outputPath = "output.txt"; // 建议用绝对路径避免工作目录问题 try { // 用bash -c 执行完整的shell命令 String[] command = {"/bin/bash", "-c", lexerPath + " < " + path + " > " + outputPath}; ProcessBuilder pb = new ProcessBuilder(command); Process process = pb.start(); // 等待执行完成并检查退出码 int exitCode = process.waitFor(); if (exitCode != 0) { try (InputStream err = process.getErrorStream(); BufferedReader errReader = new BufferedReader(new InputStreamReader(err))) { StringBuilder errorMsg = new StringBuilder(); String line; while ((line = errReader.readLine()) != null) { errorMsg.append(line).append(System.lineSeparator()); } throw new RuntimeException("mylexer执行失败,退出码:" + exitCode + ",错误信息:" + errorMsg); } } // 读取生成的output.txt内容 try (BufferedReader reader = new BufferedReader(new FileReader(outputPath))) { String line; while ((line = reader.readLine()) != null) { result.append(line).append(System.lineSeparator()); } } } catch (IOException | InterruptedException e) { e.printStackTrace(); throw new RuntimeException("调用mylexer时发生错误", e); } return result.toString().trim(); }
Windows系统
把命令改成调用cmd.exe /c即可:
String[] command = {"cmd.exe", "/c", lexerPath + " < " + path + " > " + outputPath};
额外注意事项
- 工作目录验证:可以通过
System.getProperty("user.dir")查看Java程序的当前工作目录,确保相对路径的正确性。 - 权限问题:类Unix系统下要给mylexer添加可执行权限,执行
chmod +x mylexer即可。 - 错误流处理:一定要读取
Process的错误流,否则如果mylexer执行出错,错误信息会被缓冲,可能导致程序挂起或无法排查问题。
内容的提问来源于stack exchange,提问作者Jacobo
相关产品推荐
相关产品推荐

