2013-03-30 74 views
0

我想在C中實現日誌記錄功能並將消息記錄到stdout和某個文件。 我想寫一些像fprintf(註銷,「味精」);以某種方式聲明FILE *註銷這將重定向字符串到標準輸出和一些文件。可能嗎?通過一次操作寫入兩個文件描述符

+0

創建自己的功能,輸出到兩個文件和stdout。 –

+0

我有像dump_MY_OWN_TYPE(類型)的功能,並希望保持它像dump_MY_OWN_TYPE(TYPE,FILE * F),所以我可以稱它們爲dump_MY_OWN_TYPE(TYPE,stdout)或dump_MY_OWN_TYPE(TYPE,註銷) –

回答

2

你顯然需要一個FILE狀物體重定向其寫入兩個基本FILE S(stdout和日誌文件)。標準C不允許以任何方式「繼承」對象,所以這在C中是不可能的。然而,GNU libc does,所以如果你的程序只有Linux,你可以用一些編程來實現。由於這是非常不便攜的,所以強烈建議不要。

實現此目的的更便捷的方法是寫入管道並創建一個進程或線程,以便從管道中讀取並寫入兩個底層文件。例如,假設POSIX:

FILE *tee_file(FILE *fp1, FILE *fp2) 
{ 
    int fds[2]; 
    if (pipe(fds)) 
    return NULL; 
    switch (fork()) { 
    case 0: { 
     char buf[512]; 
     int nread; 
     FILE *r = fdopen(fds[0], "r"); 
     close(fds[1]); 
     while ((nread = fread(buf, 1, sizeof buf, r)) { 
     fwrite(buf, 1, nread, fp1); 
     fwrite(buf, 1, nread, fp2); 
     } 
     _exit(0); 
    } 
    case -1: 
     return NULL; 
    } 
    close(fds[0]); 
    return fdopen(fds[1], "w"); 
} 

/* after calling "fp = tee_file(fp1, fp2)", writes to fp 
    end up in fp1 and fp2. */ 

兩種方法增加併發症的一個很好的協議,你的程序應該通過一個很好的理由是合理的。你想要的是使用一個允許寫入多個輸出的日誌框架(他們都會這樣做),或者按照H2CO3的答案所述寫出你自己的日誌框架。

+0

謝謝。所以標準的C庫不允許它,我需要擺脫這個想法。 –

+0

@DennisYurichev你可以在Unix上用單獨的線程或進程來完成它,請參閱編輯過的答案,但除非你有一個很好的理由(比如支持只接受stdio對象的第三方庫)作爲參數)。 – user4815162342

1

爲什麼不讓自己的日誌功能?

int log_fprintf(FILE *stream, const char *restrict fmt, ...) 
{ 
    va_list args; 

    va_start(args, fmt); 
    vfprintf(stream, fmt, args); 
    va_end(args); 

    va_start(args, fmt); 
    int n = vfprintf(stdout, fmt, args); 
    // conceptually, rather `stderr`, please! 
    va_end(args); 

    return n; 
} 
+0

,因爲我有像dump_MY_OWN_TYPE (類型),並希望保持它像dump_MY_OWN_TYPE(類型,文件* f),所以我可以稱它們爲dump_MY_OWN_TYPE(TYPE,stdout)或dump_MY_OWN_TYPE(TYPE,註銷) –

+0

@DennisYurichev現在我完全不明白。 .. – 2013-03-30 08:46:53

+0

想象一下複雜的數據類型:struct cplx {float re; float im; };想象一下,翻車機功能需要將這兩個字段放入FILE中:dump_cplx(struct cplx *,FILE *) –

1

如果這是在Linux上,你可以打開一個管道到tee命令:

FILE *logout = popen("tee logfile", "w"); 
+0

非常優雅,+1 – user4815162342

+0

這或多或少是我使用的,但根據您的使用情況,存在一些可能影響也可能無關緊要的問題:如果您從命令行運行程序,那麼孩子過程(你的'tee'程序)在正常情況下不需要衝洗,更有趣的是,當你的程序結束時,T形開關暫時保持打開狀態,這意味着你不會像以前那樣得到及時的回覆('tee'仍然寫入屏幕一會兒,這意味着你的提示被埋在文本中)。 總而言之,這種方法「非常」的作品,它的污垢很簡單,所以... –

+0

@scott_fakename我期望'tee'使用stdio,默認緩衝。所以如果它的標準輸出(它從你的進程繼承)到達一個終端,它將被行緩衝;如果stdout被重定向到文件或管道,它將被完全緩衝。我沒有看到爲什麼'tee'在它的輸入管道上得到EOF之後會繼續運行很多的原因;當它讀取EOF時,它應立即刷新其所有緩衝區並退出。 – Barmar