有时候,我们编码时会使用printf或fprintf去打印输出调试信息或者报错信息,但正常这样去打印,只会显示在终端,如果终端关闭了,或者系统宕机了等,这些输出信息就没有了,为了将这些重要的信息保存下来,可以输出重定向到文件,将这些信息直接输出到文件中保存着。
Linux的本质就是一切皆文件,输入输出设备也是以文件形式存在和管理的。
任何一个程序在Linux中运行,Linux系统都会为其创建3个已经打开的stream,分别用来输入(0:stdin),输出(1:stdout),打印诊断和错误信息(2:stderr)。通常他们会被连接到用户终端。这3个句柄的类型为指向FILE的指针。可以被fprintf、fread等函数使用,他们在程序开始启动后,stdin, stdout, and stderr 的文件描述符是 0, 1和2,其它的文件描述符则排在其后。
注意:stderr是不缓存的,stdout则是有缓存。
意思是:有缓存功能的,直到遇到回车'\n'才会进行打印输出,否则一直留在缓冲区里;而没有缓存功能的没有任何限制,直接打印输出。例:
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv) {
for (int i = 0; i < 5; i++) {
//fprintf(stdout, "This is stdout[%d]\n", i);
fprintf(stdout, "This is stdout[%d]", i);
sleep(1);
}
fprintf(stdout, "\n");
for (int i = 0; i < 5; i++) {
fprintf(stderr, "This is stderr[%d]", i);
sleep(1);
}
fprintf(stderr, "\n");
sleep(5);
return 0;
}
可以看出,第一个for循环中输出的语句是一起输出的,它是遇到fprintf(stdout, "\n");这行代码输出的回车后一起输出的。由此可以证明,stdout真的是带有缓存的,直到遇到回车后会输出。stderr却不受影响,正常输出。
如果需要使stdout正常输出,则加上"\n"即可!如上面注释的代码!
思考:很多时候我们会用printf打印信息来调试程序,但是如果终端关掉了,那怎么显示printf的调试信息呢?
重定向
1. >
运行程序时,加上 "> 文件名",即可将代码中标准输出(stdout)的字符串输出到指定文件中。值得注意的是,标准出错(stderr)无法使用此种方式输出到文件。例:
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv) {
printf("输出重定向:printf...\n");
fprintf(stdout, "输出重定向:fprintf(stdout)...\n");
fprintf(stderr, "输出重定向:fprintf(stderr)...\n");
perror("输出重定向:perror...\n");
return 0;
}
正常运行:
(最后输出的“:Success”是perror输出的,因为errno全局变量没有存储报错标志,所以输出Success)
输出重定向到文件:
可以看出,标准输出的已经输出到文件中了。
那么标准出错又该如何输出到文件呢?在运行尾部继续输入“2>&1”即可。
例如:./redirector > test.log 2>&1
全都输出到文件中了;但是,它是先输出标准出错,然后再输出标准输出,为什么呢?我觉得应该是缓存所导致的!
另外,使用“>”重定向到文件,会覆盖掉之前的信息,那么如何追加呢?
2. >>
使用“>>”即可达到追加效果。 ./redirector >> test.log 2>&1
3. freopen
FILE *freopen(const char *path, const char *mode, FILE *stream);
path:文件名
mode:
mode | 描述 |
---|---|
r | 读方式打开文件,该文件必须存在。 |
r+ | 读写方式打开文件,该文件必须存在。 |
w | 写方式打开文件,文件不存在则创建,存在则覆盖。 |
w+ | 读写方式打开文件,文件不存在则创建,存在则覆盖。 |
a | 追加方式打开文件,尾部追加,文件不存在则创建。 |
a+ | 追加方式打开文件,尾部追加,且可以读取。 |
stream:取值 stdout 或 stderr.
例:
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv) {
FILE *out = freopen("test1.log", "a", stdout);
//FILE *out = freopen("test1.log", "a", stderr);
printf("输出重定向:printf...\n");
fprintf(stdout, "输出重定向:fprintf(stdout)...\n");
fprintf(stderr, "输出重定向:fprintf(stderr)...\n");
perror("输出重定向:perror...\n");
fclose(stdout);
//fclose(stderr);
return 0;
}
使用stdout打开的文件,就只会将标志输出写入文件;使用stderr就会将标志出错写入文件!
当然我们一定要明白,printf输出到文件,这会引起IO中断,因此执行printf比一般的指令的效率要低很多。
总结:
平常时我们调试代码或一些小例子代码,可以使用重定向;但对于大型项目,推荐还是使用工程级的日志,例如log4或plog等。