我想在C中實現日誌記錄功能並將消息記錄到stdout和某個文件。 我想寫一些像fprintf(註銷,「味精」);以某種方式聲明FILE *註銷這將重定向字符串到標準輸出和一些文件。可能嗎?通過一次操作寫入兩個文件描述符
回答
你顯然需要一個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的答案所述寫出你自己的日誌框架。
謝謝。所以標準的C庫不允許它,我需要擺脫這個想法。 –
@DennisYurichev你可以在Unix上用單獨的線程或進程來完成它,請參閱編輯過的答案,但除非你有一個很好的理由(比如支持只接受stdio對象的第三方庫)作爲參數)。 – user4815162342
爲什麼不讓自己的日誌功能?
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;
}
,因爲我有像dump_MY_OWN_TYPE (類型),並希望保持它像dump_MY_OWN_TYPE(類型,文件* f),所以我可以稱它們爲dump_MY_OWN_TYPE(TYPE,stdout)或dump_MY_OWN_TYPE(TYPE,註銷) –
@DennisYurichev現在我完全不明白。 .. – 2013-03-30 08:46:53
想象一下複雜的數據類型:struct cplx {float re; float im; };想象一下,翻車機功能需要將這兩個字段放入FILE中:dump_cplx(struct cplx *,FILE *) –
如果這是在Linux上,你可以打開一個管道到tee
命令:
FILE *logout = popen("tee logfile", "w");
非常優雅,+1 – user4815162342
這或多或少是我使用的,但根據您的使用情況,存在一些可能影響也可能無關緊要的問題:如果您從命令行運行程序,那麼孩子過程(你的'tee'程序)在正常情況下不需要衝洗,更有趣的是,當你的程序結束時,T形開關暫時保持打開狀態,這意味着你不會像以前那樣得到及時的回覆('tee'仍然寫入屏幕一會兒,這意味着你的提示被埋在文本中)。 總而言之,這種方法「非常」的作品,它的污垢很簡單,所以... –
@scott_fakename我期望'tee'使用stdio,默認緩衝。所以如果它的標準輸出(它從你的進程繼承)到達一個終端,它將被行緩衝;如果stdout被重定向到文件或管道,它將被完全緩衝。我沒有看到爲什麼'tee'在它的輸入管道上得到EOF之後會繼續運行很多的原因;當它讀取EOF時,它應立即刷新其所有緩衝區並退出。 – Barmar
- 1. 寫作文件描述符
- 2. 寫入多個文件描述符
- 3. epoll文件描述符操作
- 4. 通過文件描述符 - Execve(typecast)
- 5. 對UNIX文件描述符的短寫操作
- 6. 如何通過文件描述符編寫一個數字數組
- 7. 將0個字符寫入文件描述符
- 8. ClearCase簽入操作失敗:無法關閉文件描述符0:錯誤的文件描述符
- 9. 對同一文件的兩個文件描述符
- 10. 寫入文件描述符3而不寫入磁盤?
- 11. 使用寫入將整數寫入文件描述符?
- 12. 替換寫入文件描述符的最後一行
- 13. 等待可讀文件描述符和可寫文件描述符
- 14. 如何使一個文件描述符
- 15. 通過不同(共享)操作寫入同一文本文件
- 16. 文件描述符用XML編寫
- 17. 文件描述符飢餓和阻斷文件描述符
- 18. 使用Linux套接字寫入錯誤文件描述符()錯誤文件描述符C
- 19. 使用文件描述符過程
- 20. 操作Python中select.select的文件描述符
- 21. PHP - $ .POST通過兩個文件兩次
- 22. Node.js的FIFO - 過程掛起寫文件描述符
- 23. 文件描述符如何工作?
- 24. 從文件描述符中讀取/寫入偏移量
- 25. 如何寫入Bash中的命名文件描述符?
- 26. 寫入Python子進程的文件描述符3 .Popen對象
- 27. 寫入文件描述符時的epoll行爲
- 28. 對同一個文件的多個文件描述符,C
- 29. 我可以通過另一個UDS文件描述符通過c或C++中的另一個UDS連接
- 30. c strcpy文件描述符
創建自己的功能,輸出到兩個文件和stdout。 –
我有像dump_MY_OWN_TYPE(類型)的功能,並希望保持它像dump_MY_OWN_TYPE(TYPE,FILE * F),所以我可以稱它們爲dump_MY_OWN_TYPE(TYPE,stdout)或dump_MY_OWN_TYPE(TYPE,註銷) –