Java IO 相关 Process 执行命令获取输出 输出很大该怎么读取? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
gzk329
V2EX    程序员

Java IO 相关 Process 执行命令获取输出 输出很大该怎么读取?

  •  
  •   gzk329 2022-11-09 09:47:43 +08:00 2714 次点击
    这是一个创建于 1148 天前的主题,其中的信息可能已经有所发展或是发生改变。

    例如:

    读 InputStream 标准输出流,输出流东西很多 发现正常读取的时候 process 已经退出了 process.waitFor()方法 等待会导致缓冲区被填满,然后阻塞 思路是在 waitFor()前,异步地去读取输出流中的内容 但是不生效 

    简单代码 我写一块儿了 缩进比较恶心 主要是有什么好的解决思路吗?

    Process process; try { process = runtime.exec(commands); ThreadPools.LOG_COLLECT.execute(()->{ try (InputStream in = process.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(in))) { String line; File destfile = new File(...); while ((line = br.readLine()) != null) { FileUtils.writeStringToFile(destfile, line + "\n", StandardCharsets.UTF_8, true); } } catch (IOException e) { //exception handler } }); process.waitFor(); } catch (IOException | InterruptedException e) { //exception handler } 
    27 条回复    2022-11-09 15:31:21 +08:00
    gzk329
        1
    gzk329  
    OP
       2022-11-09 09:54:41 +08:00
    还有一个在这句 process = runtime.exec(commands);打一个断点就能正常获取输出流 全局或者线程断点都 OK 因为是单线程
    不打断点 就拿不到输出流
    fengyiqiao
        2
    fengyiqiao  
       2022-11-09 10:26:39 +08:00
    用 ProcessBuilder 重定向输出到文件
    Pantheoon
        3
    Pantheoon  
       2022-11-09 10:31:51 +08:00
    apache 有个封装了调用本地命令的类库可以试试
    tyrantlucifer
        4
    tyrantlucifer  
       2022-11-09 10:50:45 +08:00
    @Pantheoon #3 是哪个呀,能否指点一下?
    Pantheoon
        5
    Pantheoon  
       2022-11-09 11:01:15 +08:00   1
    tyrantlucifer
        6
    tyrantlucifer  
       2022-11-09 11:16:02 +08:00
    @Pantheoon #5 感谢您,之前是我是自己封装了一个,但我总感觉有现成的可以用,今天又学到了新东西。
    gzk329
        7
    gzk329  
    OP
       2022-11-09 11:17:41 +08:00
    @fengyiqiao java 中这些本质上都是一套吧 命令里边 1>file 或者是 processBuilder 里边重定向到文件都是 走的一套逻辑,都被缓冲区大小限制的,都不行。 命令直接在 bash 中是可以执行的
    gzk329
        8
    gzk329  
    OP
       2022-11-09 11:29:06 +08:00
    @Pantheoon 谢谢,不过这个好像主要是对不同环境的命令做了自动匹配,并没有处理这个问题
    senninha
        9
    senninha  
       2022-11-09 11:30:48 +08:00
    可能是 stderr buffer 满了,stderr 也整个异步线程去读。
    gzk329
        10
    gzk329  
    OP
       2022-11-09 11:31:13 +08:00
    还有一个在这句 process = runtime.exec(commands); 之前加一个线程休眠 3s 也能解决问题?有人知道这可能是什么原因吗?是在这句之前,我的理解是命令还没有开始执行呢 先休眠三 s ,就可以执行之后的 process.waitfor 然后异步消费输出流那套逻辑了,这是为啥呀?
    fengyiqiao
        11
    fengyiqiao  
       2022-11-09 11:32:36 +08:00
    缓冲区是指主进程和子进程之间的缓冲区,1>file 和 ProcessBuilder 重定向不用这个缓冲区。你可以试一下
    gzk329
        12
    gzk329  
    OP
       2022-11-09 11:35:56 +08:00
    @senninha 这个我也试过 能读到 error 流,我的这个命令是获取 spark 作业的聚合日志,error 输出告诉我找不到日志。
    但我这个逻辑是在作业程序结束后才会执行的 所以不应该获取不到日志输出的。
    然后我开始想的是在异步读输出前先休眠,或者直接循环读,读到有结果才停止,但是不生效。
    gzk329
        13
    gzk329  
    OP
       2022-11-09 11:36:53 +08:00
    @fengyiqiao 我试过 读取来的日志文件是空的
    luman
        14
    luman  
       2022-11-09 11:40:19 +08:00
    直接 inputstream.transferTo 呢
    fengyiqiao
        15
    fengyiqiao  
       2022-11-09 12:17:34 +08:00
    @gzk329 那有可能你的输出全是 stderr ,而不是 stdout ,或者有别的问题。我之前用 ProcessBuilder 就是因为 Process 会阻塞
    xboxv
        16
    xboxv  
       2022-11-09 13:06:56 +08:00
    猜测是你的 command 的问题,command 对应的输出流没有正常的结束,导致读取阻塞。command 发出来看下
    gzk329
        17
    gzk329  
    OP
       2022-11-09 13:09:41 +08:00
    @xboxv 我的 command 就很简单的一句
    String[] commands = {BIN_BASH, "-c", "yarn logs -applicationId " + applicationId};
    fridaycatye
        18
    fridaycatye  
       2022-11-09 13:36:22 +08:00
    GobblerThread errorGobbler = new GobblerThread(process.getErrorStream(), "ERROR");
    GobblerThread outputGobbler = new GobblerThread(process.getInputStream(), "OUTPUT");
    开 2 个线程把输出流读出来就行了
    Huelse
        19
    Huelse  
       2022-11-09 13:44:46 +08:00
    https://alexn.org/blog/2022/10/03/execute-shell-commands-in-java-scala-kotlin/#java

    最近刚借鉴了类似实现跑 ffmpeg ,不过我是 scala ,最后没有采用他的实现
    aguesuka
        20
    aguesuka  
       2022-11-09 13:48:44 +08:00
    @gzk329 命令有问题, 最后一个字符串应该按照空格拆分
    aguesuka
        21
    aguesuka  
       2022-11-09 13:52:27 +08:00
    @aguesuka 看错了, bash -c 确实不用
    xboxv
        22
    xboxv  
       2022-11-09 13:57:35 +08:00
    @gzk329 命令应该没什么问题, 进程的输出有可能在错误流,process.getInputStream();改为 getErrorStream 试试
    aguesuka
        23
    aguesuka  
       2022-11-09 14:01:15 +08:00
    sleep 三秒就正常的话, 感觉这段代码是能运行的, 而是执行的时机不对
    xboxv
        24
    xboxv  
       2022-11-09 14:13:44 +08:00
    @aguesuka 什么代码要 sleep 三秒?代码贴一下
    quicksand
        25
    quicksand  
       2022-11-09 15:11:44 +08:00
    我试了你的代码,读取一个 60M 的文本没任何异常
    gzk329
        26
    gzk329  
    OP
       2022-11-09 15:27:33 +08:00
    @xboxv 不需要三秒,我之前测了一下 最少大概 500ms 有时可以 800ms 稳定可以
    gzk329
        27
    gzk329  
    OP
       2022-11-09 15:31:21 +08:00
    @quicksand 我之前也怀疑 是在执行命令前 sleep 一会儿 按理说这时候命令还没有执行
    但是这个方法执行的条件是 spark 作业已经进入最终态了 我怀疑是不是查到 spark 进入最终态了 然后其实它还没有执行完
    yarn logs 这个命令是拿的 sparkd 的聚合日志 需要 spark 作业已经执行完
    这个中间是不是有个时间差 导致的
    所以我又去这个日志收集之前做了一个 sleep 好像没用 就很奇怪
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5276 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 139ms UTC 03:24 PVG 11:24 LAX 19:24 JFK 22:24
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86