仅通过一个操作写入两个文件描述符

时间:2013-03-30 08:40:25

标签: c logging file-descriptor

我想在C中实现日志记录功能,并将消息记录到stdout和某个文件。 我想写一些像fprintf(logout,“msg”);以某种方式声明FILE * logout,它将字符串重定向到stdout和一些文件。可能吗?

3 个答案:

答案 0 :(得分:2)

您显然希望像FILE这样的对象将其写入重定向到两个基础FILE s(stdout和日志文件)。标准C不允许以任何方式“子类化”FILE个对象,所以这在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的回答编写你自己的记录框架。

答案 1 :(得分:2)

如果是在Linux上,您可以打开tee命令的管道:

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

答案 2 :(得分: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;
}