[英]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.