日志备份和轮转系统#
实现一个日志文件备份和轮转系统,当文件大小超过限制时自动创建备份并清空原文件。核心功能如下:
文件大小监控:检查指定文件是否超过 10KB 的限制
备份管理:最多保留 5 个备份文件,采用轮转策略
自动清理:当备份数量达到上限时,自动删除最旧的备份
压缩存储:备份完成后将文件压缩为 tar.gz 格式以节省空间
内容清空:备份后清空原文件内容
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <time.h>
#include <libgen.h>
#define MAX_SIZE (10 * 1024) // 10KB
#define MAX_BACKUPS 5
// 比较函数,用于排序文件时间
int compare_files(const void* a, const void* b) {
struct stat st_a, st_b;
stat(*(const char**)a, &st_a);
stat(*(const char**)b, &st_b);
return st_a.st_mtime - st_b.st_mtime;
}
// 检查文件大小并进行备份
int check_and_backup_file(const char* path) {
struct stat st;
// 检查文件是否存在
if (stat(path, &st) != 0) {
perror("stat failed");
return -1;
}
// 检查文件大小是否超过限制
if (st.st_size <= MAX_SIZE) {
return 0; // 文件大小未超过限制
}
// 获取文件名和目录
char* path_copy = strdup(path);
char* dir = strdup(dirname(path_copy));
char* base_name = basename(path);
// 查找现有的备份文件
DIR* dp = opendir(dir);
if (!dp) {
perror("opendir failed");
free(path_copy);
return -1;
}
char* backup_files[MAX_BACKUPS] = {0};
int backup_count = 0;
struct dirent* entry;
char pattern[256];
snprintf(pattern, sizeof(pattern), "%s__", base_name);
while ((entry = readdir(dp)) != NULL && backup_count < MAX_BACKUPS) {
if (strstr(entry->d_name, pattern) == entry->d_name) {
char full_path[1024];
snprintf(full_path, sizeof(full_path), "%s/%s", dir, entry->d_name);
backup_files[backup_count++] = strdup(full_path);
}
}
closedir(dp);
free(path_copy);
// 确定下一个备份编号
int next_number = 1;
if (backup_count >= MAX_BACKUPS) {
// 按修改时间排序,找到最老的文件
qsort(backup_files, backup_count, sizeof(char*), compare_files);
char* oldest = backup_files[0];
// 提取编号
char* num_start = strrchr(oldest, '_') + 1;
if (num_start) {
next_number = atoi(num_start);
}
// 删除最老的备份文件
remove(oldest);
free(oldest);
// 重新组织备份文件数组
for (int i = 1; i < backup_count; i++) {
backup_files[i - 1] = backup_files[i];
}
backup_count--;
} else {
// 查找最大的现有编号
int max_number = 0;
for (int i = 0; i < backup_count; i++) {
char* num_start = strrchr(backup_files[i], '_') + 1;
if (num_start) {
int num = atoi(num_start);
if (num > max_number) {
max_number = num;
}
}
free(backup_files[i]);
}
next_number = max_number + 1;
}
// 创建新的备份文件名
char new_name[1024];
snprintf(new_name, sizeof(new_name), "%s/%s__%03d", dir, base_name, next_number);
free(dir);
// 执行备份
char cmd[2048];
snprintf(cmd, sizeof(cmd), "cp %s %s", path, new_name);
if (system(cmd) != 0) {
perror("Failed to execute backup command");
return -1;
}
// 安全地清除 path 文件内容
snprintf(cmd, sizeof(cmd), "echo -n > %s", path);
if (system(cmd) != 0) {
perror("Failed to clear file");
return -1;
}
// 打包压缩(这里使用 tar.gz 作为示例)
snprintf(cmd, sizeof(cmd), "tar -czf %s.tar.gz -C %s %s && rm %s",
new_name, dirname(strdup(new_name)), basename(strdup(new_name)), new_name);
if (system(cmd) != 0) {
fprintf(stderr, "tar -czf failed\n");
return -1;
}
printf("%s is backed up to %s.tar.gz\n", path, new_name);
return 1;
}
// 使用示例
int main() {
const char *filename = "test.log";
int result = check_and_backup_file(filename);
if (result == 1) {
printf("backup success\n");
} else if (result == 0) {
printf("file size is normal\n");
} else {
printf("backup failed\n");
}
return 0;
}