#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <stdbool.h>
void logSuccess(char *format, ...)
{
bool dir_missing;
struct stat v2;
char s[1024] = {0};
FILE *stream = NULL;
const char *log_filename = "XuewuSo.txt";
char *log_directory = "/home/tlbb/Server/Log";
va_list va;
va_start(va, format);
snprintf(s, sizeof(s), "%s/%s", log_directory, log_filename);
dir_missing = stat(log_directory, &v2) != 0 && errno == ENOENT;
if (dir_missing) //&& mkdir(log_directory, 0755)
{
perror("Failed to create log directory");
}
else
{
stream = fopen(s, "a");
if (stream)
{
vfprintf(stream, format, va);
fputc('\n', stream);
fclose(stream);
printf("Success log written to %s\n", s);
}
else
{
perror("Failed to open log file");
}
}
va_end(va);
}
int main()
{
logSuccess("This is a test message: %d", 42);
return 0;
}
代码解析
变量和头文件部分
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdbool.h>
- stdio.h: 用于文件操作(fopen、fclose、fputc)和标准输出(printf)。
- stdarg.h: 用于处理变长参数的宏和类型(va_list、va_start、va_arg、va_end)。
- string.h: 提供字符串处理函数(snprintf、memset)。
- sys/stat.h: 提供 stat 函数和 mkdir 函数,用于检查文件/目录状态和创建目录。
- errno.h: 用于检查全局错误码 errno。
- stdbool.h: 提供布尔类型 bool,使代码更具可读性。
函数定义及参数说明
void logSuccess(char *format, ...)
- 函数名称:logSuccess
- 参数:
- char *format:格式化字符串,用于指定日志内容。
- ...:省略号表示可变参数,支持传入任意数量和类型的额外参数。
局部变量
bool dir_missing; // 布尔值,用于检查目录是否存在。
char s[1024]; // 字符数组,存储完整的日志文件路径。
char *path; // 字符串指针,指向日志目录的路径。
const char *log_filename; // 字符串常量,指向日志文件名。
FILE *stream; // 文件指针,表示打开的日志文件流。
va_list va; // 可变参数列表,用于处理 format 之后的参数。
初始化变量和目录路径
va_start(va, format);
memset(s, 0, sizeof(s));
stream = NULL;
v6 = "XuewuSo.log";
path = "/home/tlbb/Server/Log";
- va_start(va, format):初始化 va,从而可以访问 ... 传入的参数。
- memset(s, 0, sizeof(s)):将字符数组 s 全部清零,确保它不会有未定义的内容。
- stream = NULL:初始化文件指针。
- v6 和 path:分别设置日志文件名和日志目录的路径。
构建日志文件路径
snprintf(s, sizeof(s), "%s/%s", path, v6);
snprintf:格式化并安全地写入字符数组 s,生成完整的日志文件路径,例如:/home/tlbb/Server/Log/XuewuSo.log
检查目录是否存在
dir_missing = stat(log_directory, &v2) != 0 && errno == ENOENT;
stat(log_directory, (int)v2):检查 log_directory 指向的目录是否存在。
- 如果 stat 返回非零并且 errno 是 ENOENT(值为 2,表示文件/目录不存在),v1 将被设置为 true,表示目录不存在。
打开日志文件并写入日志内容
else
{
stream = fopen(s, "a");
if (stream)
{
vfprintf(stream, format, va);
fputc('\n', stream);
fclose(stream);
printf("Success log written to %s\n", s);
}
else
{
perror("Failed to open log file");
}
}
- fopen(s, "a"):以追加模式打开日志文件。如果文件不存在,fopen 会创建它。
- vfprintf:将变长参数列表 va 中的内容写入文件。
- fputc('\n', stream):追加一个换行符。
- fclose(stream):关闭文件。
- 如果打开文件失败,使用 perror 打印错误原因。
清理
va_end(va)
:清理变长参数列表。