簡體   English   中英

為什么`getline`可以盡快獲取管道的輸出,而`setvbuf`和`fread`不起作用

[英]Why `getline` could acquire the output of the pipe as soon as possible, whereas `setvbuf` & `fread` does not work

我希望盡快看到popen執行的命令的輸出。所以我把popen返回的文件流的緩沖類型改為line buffered。 根據文檔setvbuf似乎可以實現這一目標 我在Ubuntu16.4上做了一個簡單的測試,確實沒有任何區別

這是我用來做上述測試的代碼片段:

#include <stdio.h>
#include <string.h>

int main(void)
{
    char buffer[1024];
    memset(buffer, 0, 1024);
    FILE* file = popen("bash -c \"for i in 1 2 3 4 5;do echo -e -n 'thanks a lot\n'; sleep 1; done\" ", "r");
    


    if(NULL != file)
    {
        int size;
        printf("setvbuf returns %d\n", setvbuf(file, NULL, _IOLBF, 0)); 
        while((size = fread(buffer, 1, 1024, file))>0)
        {
            printf("size=%d\n", size);
            memset(buffer, 0, 1024);
        }
    }
    
    return 0;
}

這是在Ubuntu16.04上運行的代碼片段的輸出:

setvbuf returns 0
//about five seconds later
size=65

根據文件,其中說:

函數 setvbuf() 成功時返回 0。

根據上面的輸出, setvbuf(file, NULL, _IOLBF, 0)已經成功地將popen返回的file的緩沖類型設置為行緩沖。但是上述代碼片段的輸出表明它仍然使用默認的緩沖塊。

但是當我嘗試getline時,它​​可以達到目標,這真的出乎我的意料。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(void)
{
    FILE* file = popen("bash -c \"for i in 1 2 3 4 5;do echo -e -n 'thanks a lot\n'; sleep 1; done\" ", "r");
 
    char* line=NULL;
    size_t len;
    if(NULL != file)
    {
//      std::cout << setvbuf(file, NULL, _IOLBF, 0) << std::endl; //setvbuf has not been called
        while(getline(&line, &len, file)>0)
        {
            printf("strlen(line)=%lu\n", strlen(line));
            free(line);
            line = NULL;
        }
    }
    
    free(line);
    return 0;
}

這是輸出:

//one second later
strlen(line)=13
//one second later
strlen(line)=13
//one second later
strlen(line)=13
//one second later
strlen(line)=13
//one second later
strlen(line)=13

我真的很清楚為什么getline可以盡快獲取管道的輸出,而setvbuf & fread不起作用。

一旦到達換行符, getline就會停止讀取。 fread一直讀取,直到它讀取與您指定的數據一樣多的數據(在您的情況下為 1024 字節),或者遇到 EOF 或錯誤。 這與緩沖無關。 您可能想查看read以查看它是否更接近您想要的。

@Jeremy Friesner 的回答:

根據我的經驗,對 setvbuf(stdout, NULL, _IONBF, 0) 的調用需要在子進程內執行才能獲得您想要的行為。 (當然,如果子進程的可執行文件是您控制的,而不是 /bin/bash,那么實現起來要容易得多)。 父進程中的 popen() 無法為您提供子進程尚未提供給它的數據。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM