当运行命令以及如何逐行捕获输出时,popen会经历什么时间间隔?

问题描述:

可以说我在下面有这段代码,我用它来运行一个简单的命令,如ls,并假设输出为100行。当运行命令以及如何逐行捕获输出时,popen会经历什么时间间隔?

当我们在下面的代码中做cout << buff时,输出是逐字节地,逐位地或逐行地进行流传输还是逐行传输?

可以说我们要打印new_line!因为我们正在流式传输,所以每一个新行的字符串结束cout<<buff。我们该怎么做?

我想在这while循环中,我们应该有一些应该检查,它只是流(或即将流)\n到我们的stringstream output,它决定之后(或之前)做一些它流进输出。

最初,我只作为数据结构它来存储,所以我只需要知道如何检查\n因为我们bufferring并往哪里放,增加了new_line!或任何我想做的功能。

下面的代码:

#include <iostream> 
#include <stdio.h> 

using namespace std; 
// imaginary 
// stringstream output; 


int main() { 
    FILE *in; 
    char buff[512]; 

    if(!(in = popen("ls -sail", "r"))){ 
     return 1; 
    } 

    while(fgets(buff, sizeof(buff), in)!=NULL){ 
      // output << buff; 
      // if there is a new line 
      // output << "new_line!"; 

     cout << buff; 
    } 
    pclose(in); 

    return 0; 
} 

如果使用GNU libc的,那么你可以使用getline(),而不是fgets。有关更详细的解释,请参阅here

否则,请使用系统提供的任何设施读取FILE*中的一行。如果你真的找不到这样的设施(这将是非常令人惊讶的),那么最糟糕的是,你总是可以使用this approachfgets也是一个很好的解决方案,只要你考虑缓冲区大小的限制,如果需要的话可以自己做更多的缓冲(检查the doc,一切都被解释了)。

你必须记住的事情是,popen只是返回FILE*所以任何可以在标准文件上工作的东西也适用于你的情况。网络上有很多例子。


现在对于你的问题的“时间间隔”部分,恐怕没有多大意义。首先,它取决于外部命令向标准输出打印新数据的时间间隔。无论如何,只要外部命令写入它,您就可以在程序中读取它。

+0

谢谢,我不确定'getline()'是否可以工作,谢谢你的清除! – Logan 2013-03-01 22:59:53

就像fget与stdio。它会一直等到EOF(程序关闭)或缓冲区被填满。

因此,while循环的每次迭代将获得512字节的数据,或者程序终止或stdio关闭后的剩余部分。

你可以用这样的小程序测试:

#include <thread> 
#include <chrono> 
#include <iostream> 

int main() { 
    std::cout << "hello" << std::endl; 
    std::this_thread::sleep_for(std::chrono::seconds(5)); 
    std::cout << " world" << std::endl; 
} 

,你会不顾长时间休眠状态它仍然会尝试读取512个字节和结束时的stdout做平仓通知。

要以符合标准的方式管理实际的分块,您可以使用std::fgetc并构建自己的缓冲区。

http://en.cppreference.com/w/cpp/io/c/fgetc

你自己的函数getline可能是这样的:

std::string get_line(FILE* f) { 
    char c; 
    std::string out; 
    while(c=std::fgetc(f)!='\n' && c!=EOF) { 
     out+=c; 
    } 
    out+='\n'; 
    return out; 
} 


//... 

//usage 
while(!std::feof(in)) { 
    cout << get_line(in); 
} 
+0

谢谢你的例子,它真的帮助:) – Logan 2013-03-01 23:12:42

管,因为它涉及的(直到它到达一些实施限制,可能无法轻易找到将缓存中的数据 - 但它是“充足的” - 在这个点上,当ls写入它时,管道将“阻塞”,因此ls将停止),除非您更快地读出它,在这种情况下,您的线程将被阻塞。如果您输出到屏幕上,则很可能您的输出会限制速度。

这样的管道不是“块状”或“线路缓冲”的 - 它只是一根管道 - 任何一端放在另一端。当然,如果“文件管理”的内部请求4000字节,则在读取操作完成之前可能需要等到4000字节通过另一端。但最有可能的是fgets的内部是理智的,不会一次要求大量的数据。