Linux C 重定向标准输出到文件或内存
先看示例
以下示例将标准输出重定向到一块内存区域,结束时,可以获取这块内容,方便单元测试。
void *m = fd_redirect_to_memory_begin(STDOUT_FILENO); // STDOUT_FILENO等于1
printf("123");
puts("456");
char *result = fd_redirect_to_memory_end(m);
// result 这里就等于"123456\n"
free(result);
也可以将标准输出重定向到文件,这样,程序启动时设置一下,就可以将所有屏幕日志导向文件。
FILE *fp = fopen(LOG_FILE_NAME, "w+");
void *m = fd_redirect_to_file_begin(STDOUT_FILENO, fp);
printf("123");
puts("456");
fd_redirect_to_file_end(m);
// 文件中的内容就等于"123456\n"
fclose(fp);
如何实现
标准输出的重定向主要使用dup和dup2函数:
int dup(int oldfd);
int dup2(int oldfd, int newfd);
dup函数将创建一个新的文件描述符,指向与oldfd相同的文件。
dup2函数会让newfd指向与oldfd相同的文件。
所以,可以先将STDOUT_FILENO通过dup函数复制一份,再使用dup2让STDOUT_FILENO指向新的位置。
核心代码如下:
// 1就是STDOUT_FILENO
// 开始重定向
int backupfd = dup(1); // backupfd会等于(比如)3,指向与stdout相同的位置
dup2(your_own_fd, 1); // 将1号fd重定向到别的文件
// 结束重定向
dup2(backupfd, 1); // 将1号fd恢复
close(backupfd) // 别忘了关闭复制出来的fd
完整代码
fd_redirect_to_file
重定向到文件的代码比较简单,需要注意fileno(fp)不一定是有效的fd就可以了。
struct redirect_file_st
{
int fno;
int dup;
};
void *fd_redirect_to_file_begin(int __fileno, FILE *fp)
{
struct redirect_file_st *__st = malloc(sizeof(struct redirect_file_st));
__st->fno = __fileno;
__st->dup = dup(__fileno);
if (__st->dup < 0)
{
free(__st);
return NULL;
}
if (dup2(fileno(fp), __fileno) < 0) // fileno(fp) may not a fd
{
close(__st->dup);
free(__st);
return NULL;
}
return __st;
}
void fd_redirect_to_file_end(void *p)
{
if (p == NULL)
{
fprintf(stderr, "fd_redirect_to_file_end: input ptr cannot be NULL.");
abort();
}
struct redirect_file_st *__st = p;
dup2(__st->dup, __st->fno);
close(__st->dup);
free(__st);
}
fd_redirect_to_memory
重定向到内存的代码略有些不一样,是因为open_memstream打开的文件流,虽然也是FILE结构,但其实是没有fd这个东西的(因为没有真实的打开文件),所以需要借助pipe来读取。
struct redirect_memory_st
{
int fno;
int dup;
int fd[2];
};
void *fd_redirect_to_memory_begin(int __fileno)
{
struct redirect_memory_st *__st = malloc(sizeof(struct redirect_memory_st));
__st->fno = __fileno;
__st->dup = dup(__fileno);
if (__st->dup < 0)
{
free(__st);
return NULL;
}
if (pipe(__st->fd) < 0)
{
close(__st->dup);
free(__st);
return NULL;
}
dup2(__st->fd[1], __fileno);
return __st;
}
char *fd_redirect_to_memory_end(void *p)
{
if (p == NULL)
{
fprintf(stderr, "fd_redirect_to_memory_end: input ptr cannot be NULL.");
abort();
}
struct redirect_memory_st *__st = p;
char *result;
size_t len;
FILE *fp = open_memstream(&result, &len);
char buf[128];
ssize_t n;
fcntl(__st->fd[0], F_SETFL, fcntl(__st->fd[0], F_GETFL) | O_NONBLOCK);
while ((n = read(__st->fd[0], buf, 128)) > 0)
{
fwrite(buf, 1, n, fp);
}
close(__st->fd[0]);
close(__st->fd[1]);
dup2(__st->dup, __st->fno);
close(__st->dup);
fclose(fp);
free(__st);
return result;
}
Disqus评论加载中...