美文网首页
调用外部程序并获得输出内容

调用外部程序并获得输出内容

作者: moriv4 | 来源:发表于2020-04-23 20:30 被阅读0次

    在做软件开发时,为了实现一个复杂功能可能需要调用其他程序。具体功能在子进程中完成,父进程获取子进程的输出来判断结果。例如编程获得硬盘分区信息这个功能。如果自己从头开始写,只能这样实现:读取硬盘前几个扇区获得分区表,再分析表中的内容。如果直接使用Linux自带的lsblk程序就非常简单,因为lsblk可以输出json字符串,父进程获得后解析即可获得分区信息。

    下面给出两种实现方案,第一种是用 Linux C 编程,另一种是用Qt框架编程。功能是:父进程创建子进程、等待子进程结束、获得子进程输出。

    1. Linux C
    // get sub process's output in parent process using pipe redirection
    #include <unistd.h>
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <error.h>
    #define BUFFSIZE 4000
    
    int main()
    {
        int pipefd[2];
        pid_t pid;
        if (pipe(pipefd) != 0)
        {
            perror("cannot create pipe");
        }
        pid = fork();
        if (pid == -1)
        {
            perror("cannot fork");
        }
        else if (pid == 0)
        {
            // child process
            close(pipefd[0]);
            int res = dup2(pipefd[1], STDOUT_FILENO);
            if (res != -1)
                execlp("lsblk", "lsblk", "--fs", "-o", "+MODEL,SIZE", "-J", NULL);
            else
            {
                perror("cannot redirect");
                exit(1);
            }
        }
        close(pipefd[1]);
        int status = -1;
        waitpid(pid, &status, 0);
    
        char buff[BUFFSIZE];
        ssize_t count = 0;
        count = read(pipefd[0], buff, BUFFSIZE - 1);
        if (count > 0)
            buff[count] = '\0';
        else
            perror("read error");
    
        // is there left data ?
        char test;
        count = read(pipefd[0], &test, 1);
    
        printf("%s\n", buff);
        if (count == 1)
            fprintf(stderr, "read incomplete data\n");
    
        close(pipefd[0]);
    
        return 0;
    }
    

    分析:

    • 创建子进程使用 fork() execlp() 函数。
    • 重定向子进程输出:pipe() dup2() 函数。先把子进程的stdout关闭,再把管道 write fd 复制到stdout对应的fd,最后execlp。子进程的输出内容写入管道中。
    • 等待子进程结束:waitpid() 函数。
    • 读取子进程输出:read() 函数,从管道中读取。
    1. Qt
    QProcess lsblk;
    lsblk.setProgram("lsblk");
    lsblk.setArguments(QStringList() << "--fs" << "-o" << "+MODEL,SIZE" << "-J");
    lsblk.start();
    lsblk.waitForFinished(1000);
    if (lsblk.exitCode() == 0)
        qDebug() << lsblk.readAllStandardOutput();
    else 
        qDebug() << lsblk.readAllStandardError();
    
    

    分析:Qt使用面向对象的思想,把进程看做类。进程类QProcess继承了QIODevice类,这样处理输入输出十分方便。使用的时候创建进程对象lsblk,设置参数并执行,等待进程结束后可以直接获取输出内容。

    这两种方法对比来看,Qt框架用起来更方便。QProcess封装了各种底层操作,同时提供强大的进程同步的函数,能轻松实现计时、读取、写入功能,还不需要担心缓冲区溢出的问题。

    相关文章

      网友评论

          本文标题:调用外部程序并获得输出内容

          本文链接:https://www.haomeiwen.com/subject/tgqzihtx.html