V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
rqxiao
V2EX  ›  Java

Java process 的一些疑问

  •  
  •   rqxiao · 2022-12-15 14:13:28 +08:00 · 1678 次点击
    这是一个创建于 709 天前的主题,其中的信息可能已经有所发展或是发生改变。
    import java.io.IOException;
    
    public class Test {
    
        public static void main(String[] args) throws IOException, InterruptedException {
    
            String command1 = "java -version";
            String command2="/Users/user1/develop/ffmpeg/ffmpeg -i /Users/user1/develop/ffmpeg/input.avi -vflpossa fps=1/5  /Users/user1/develop/ffmpeg/input.avi.%d.jpg";
            Process p=Runtime.getRuntime().exec(command1);
            ProcessHandler.dealStream(p);
            p.waitFor();
            System.out.println("结束了");
        }
    }
    
    import lombok.extern.slf4j.Slf4j;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    
    /**
     * ref: https://blog.csdn.net/weixin_33690367/article/details/86134029
     */
    @Slf4j
    public class ProcessHandler {
    
        public static String dealStream(Process process) {
            StringBuilder builder = new StringBuilder();
    
            if (process == null) {
                return null;
            }
            // 处理 InputStream 的线程
            new Thread(() -> {
                BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
                String line;
                try {
                    while ((line = in.readLine()) != null) {
                        builder.append(line);
                        log.info("input===: " + line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        in.close();
                    } catch (IOException e) {
                        // TODO 处理出错
                        e.printStackTrace();
                    }
                }
            }).start();
    
            // 处理 ErrorStream 的线程
            new Thread(() -> {
                BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream()));
                String line;
                try {
                    while ((line = err.readLine()) != null) {
                        builder.append(line);
                        log.info("错误---: " + line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        err.close();
                    } catch (IOException e) {
                        // TODO 处理出错
                        e.printStackTrace();
                    }
                }
            }).start();
    
            return builder.toString();
        }
    }
    

    1 )为啥 process 一些正常的输出都在 errorStream 里?现在有一个需求想用 ffmpeg 执行转码,如果转码出错了,是不是应该读取 标准错误输出流里 errorStream 的内容,如果 errorStream 的 StringBuilder 不为空,或者有 'error; 字符串,就可以认为是转码失败了?但现在输出测试下来怎么都在 errorstream 里。。

    结束了
    14:04:19.433 [Thread-1] INFO com.utils.ProcessHandler - 错误---: java version "1.8.0_291"
    14:04:19.436 [Thread-1] INFO com.utils.ProcessHandler - 错误---: Java(TM) SE Runtime Environment (build 1.8.0_291-b10)
    14:04:19.436 [Thread-1] INFO com.utils.ProcessHandler - 错误---: Java HotSpot(TM) 64-Bit Server VM (build 25.291-b10, mixed mode)
    

    2 ) process 机制原因会导致死锁,所以需要在 waitfor 方法之前,创建线程用于处理 inputstream 中缓冲区的数据。 不用其他线程清空 process 的缓冲区可以吗。在 process 开始后,单靠主线程读取缓冲的内容,读完了主线程再 waitfor 不可以吗。

    11 条回复    2022-12-16 00:53:58 +08:00
    xiaohundun
        1
    xiaohundun  
       2022-12-15 14:53:56 +08:00
    可能是 java -version 这个命令行的问题吧,你试试其他的呢? 比如 ls -l /
    rqxiao
        2
    rqxiao  
    OP
       2022-12-15 15:19:18 +08:00
    @xiaohundun ls -l / 是 inputStream 。。。这是什么道理
    zjb861107
        3
    zjb861107  
       2022-12-15 15:36:51 +08:00   ❤️ 1
    wolfie
        4
    wolfie  
       2022-12-15 15:37:44 +08:00   ❤️ 1
    redirectErrorStream 合并流,然后用 exitValue 判断成功?
    xiaohundun
        5
    xiaohundun  
       2022-12-15 15:58:01 +08:00
    @rqxiao 不知道哎😮‍💨有没有可能源码就写错了给输出到标准错误输出里了😂
    ysc3839
        6
    ysc3839  
       2022-12-15 16:08:58 +08:00
    感觉是 X-Y Problem https://coolshell.cn/articles/10804.html
    你要调用 ffmpeg 的话可以看看 https://github.com/bramp/ffmpeg-cli-wrapper
    xiaohundun
        7
    xiaohundun  
       2022-12-15 16:24:12 +08:00   ❤️ 1
    @rqxiao 仔细看了下 java -h ,发现人家写的很清楚,-version 就是输出到错误流
    xiaohundun
        8
    xiaohundun  
       2022-12-15 16:24:45 +08:00
    @rqxiao 你可以用 java --version
    superliy
        9
    superliy  
       2022-12-15 16:59:03 +08:00
    一个线程一个 process ,你用 ffmpeg 转码,多个线程对你没啥影响
    superliy
        10
    superliy  
       2022-12-15 17:00:15 +08:00   ❤️ 1
    ProcessBuilder pb = new ProcessBuilder(generateExecCommand(execCommand.apply(args)));
    pb.redirectErrorStream(true);
    try {
    this.process = pb.start();
    BufferedReader stdOut = new BufferedReader(new InputStreamReader(process.getInputStream()));
    stdOut.lines().forEach(line -> log.info("{}#{}", name, line));
    } catch (IOException e) {
    log.error("Failed to start process: ", e);
    }
    wangyu17455
        11
    wangyu17455  
       2022-12-16 00:53:58 +08:00   ❤️ 1
    为了不污染 stdout ,很多非格式化输出都是输出到 stderr ,比如 curl 的实时进度就是输出到 stderr
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1182 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 23:56 · PVG 07:56 · LAX 15:56 · JFK 18:56
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.