Java调用指定目录darknet.exe运行Yolo检测无法读取输出如何解决
问题根因分析
- 为什么加
start后读不到输出:cmd /c start的作用是新开一个独立的控制台窗口运行后续命令,你Java代码中启动的cmd进程在执行完start后就直接退出了,darknet的所有输出都打印到了新开的窗口中,根本不会写入到Java进程绑定的输入流,因此readLine()只能读到null。 - 为什么去掉
start后程序卡住:darknet运行时会同时向标准输出流(stdout)和标准错误流(stderr)打印内容,你的代码只读取了stdout,当stderr的缓冲区被写满后,darknet进程会被系统阻塞,等待缓冲区内容被读取,因此程序会卡住不动,只能读到前面少量的stdout输出。 - 为什么去掉
cmd参数报错:Windows系统的CreateProcess接口无法直接识别工作目录下的可执行文件(除非该目录在系统PATH环境变量中),必须通过cmd进程来解析当前工作目录下的程序路径,或者你直接写darknet.exe的完整绝对路径也可以直接调用。
解决方案
修改后的ProcessBuilder实现如下,核心优化点是:去掉start命令、合并标准输出和错误流、正确等待进程执行完成:
import java.io.*; public class YoloCaller { public static void main(String[] args) { ProcessBuilder pb = new ProcessBuilder( "cmd", "/C", // 不要加start,直接写darknet命令,让它在当前cmd进程运行 "darknet.exe detector test data\\obj.data cfg\\yolov4-obj.cfg backup\\rgbmodel\\yolov4-obj_last.weights -dont_show -ext_output C:\\Users\\felix\\Desktop\\yoloTestSet\\RGBTest\\IMG_2392.jpg" ); // 设置工作目录 pb.directory(new File("C:\\AI\\Yolo_v4\\darknet\\build\\darknet\\x64")); // 关键:合并标准输出和错误流,避免缓冲区满阻塞进程 pb.redirectErrorStream(true); try { Process process = pb.start(); // 读取合并后的输出流,编码可根据系统实际情况调整,Windows cmd默认是GBK BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream(), "GBK")); String line; while ((line = br.readLine()) != null) { System.out.println(line); } // 等待进程执行完成,可通过退出码判断是否运行成功 int exitCode = process.waitFor(); System.out.println("Darknet执行完成,退出码:" + exitCode); br.close(); process.destroy(); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } }
额外优化说明
如果你不想通过cmd调用,也可以直接把darknet.exe的完整绝对路径写在ProcessBuilder的参数里,比如"C:\\AI\\Yolo_v4\\darknet\\build\\darknet\\x64\\darknet.exe",这样就可以去掉cmd和/C参数,也不会报找不到文件的错误。
内容的提问来源于stack exchange,提问作者Hom Tanks
相关产品推荐
相关产品推荐

