概述
本文案例基于一个已有的C语言模块,该模块在之前的版本中并未包含文件日志功能。我们的目标是通过添加一个简单的日志记录方法,使得模块能够在运行时将关键信息写入到日志文件中。为了保证通用性,我们将支持Windows和Linux操作系统,并且涵盖x86和ARM架构的适配。
完整代码分析与优化
以下是我们将要优化和扩展的完整代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#ifdef WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
#define FILE_MAX_SIZE (1024 * 1024)
/*
获得当前时间字符串
@return 当前时间字符串
*/
char* get_local_time_with_ms() {
struct timeval tv;
gettimeofday(&tv, NULL);
struct tm* timeinfo = localtime(&tv.tv_sec);
char* now = malloc(32);
if (now != NULL) {
snprintf(now, 32, "%04d-%02d-%02d %02d:%02d:%02d.%03ld", (timeinfo->tm_year + 1900), timeinfo->tm_mon + 1,
timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec,
tv.tv_usec / 1000); // 毫秒信息,微秒除以1000得到毫秒
}
return now;
}
/*
获得文件大小
@param filename [in]: 文件名
@return 文件大小
*/
long get_file_size(char* filename) {
long length = 0;
FILE* fp = NULL;
fp = fopen(filename, "rb");
if (fp != NULL) {
fseek(fp, 0, SEEK_END);
length = ftell(fp);
}
if (fp != NULL) {
fclose(fp);
fp = NULL;
}
return length;
}
/*
写入日志文件
@param filename [in]: 日志文件名
@param max_size [in]: 日志文件大小限制
@param buffer [in]: 日志内容
@param buf_size [in]: 日志内容大小
@return 空
*/
void write_log_file(char* filename, long max_size, char* buffer, unsigned buf_size) {
if (filename != NULL && buffer != NULL) {
// 文件超过最大限制, 删除
long length = get_file_size(filename);
if (length > max_size) {
unlink(filename); // 删除文件
}
// 写日志
{
FILE* fp;
fp = fopen(filename, "at+");
if (fp != NULL) {
char* now = get_local_time_with_ms();
fwrite(now, strlen(now), 1, fp);
fwrite(buffer, buf_size, 1, fp);
free(now);
now = NULL;
fclose(fp);
fp = NULL;
}
}
}
}
int main(int argc, char** argv) {
int idx;
for (idx = 0; idx < 10; ++idx) {
char buffer[32];
memset(buffer, 0, sizeof(buffer));
int chars_written = snprintf(buffer, sizeof(buffer), "====> %d\n", idx);
if (chars_written > 0 && chars_written < sizeof(buffer)) {
write_log_file("log.txt", FILE_MAX_SIZE, buffer, chars_written);
#ifdef WIN32
Sleep(100); // 毫秒
#else
usleep(100 * 1000); // 毫秒
#endif
} else {
// Handle snprintf failure
// Maybe log an error or take appropriate action
}
}
return 0;
}
详细说明与优化
-
时间戳获取函数 (
get_local_time_with_ms):- 使用
gettimeofday函数获取当前时间和微秒级精度,并将其格式化为可读的时间字符串,以便于在日志中记录事件发生的时间。
- 使用
-
文件大小获取函数 (
get_file_size):- 使用文件操作函数
fopen,fseek和ftell来获取日志文件的当前大小,用于后续判断是否需要清空日志文件。
- 使用文件操作函数
-
日志写入函数 (
write_log_file):- 根据传入的日志内容,将时间戳和实际日志信息写入到指定的日志文件中。如果日志文件超过预设的最大大小限制,将会自动删除旧日志文件。
-
跨平台支持:
- 使用了预处理指令
#ifdef WIN32和#else,在Windows平台下使用Sleep函数暂停执行,Linux平台下使用usleep函数进行暂停。
- 使用了预处理指令
测试代码
为了验证日志记录功能的正确性,我们提供了以下测试代码,用于循环写入10条简单的日志信息:
int main(int argc, char** argv) {
int idx;
for (idx = 0; idx < 10; ++idx) {
char buffer[32];
memset(buffer, 0, sizeof(buffer));
int chars_written = snprintf(buffer, sizeof(buffer), "====> %d\n", idx);
if (chars_written > 0 && chars_written < sizeof(buffer)) {
write_log_file("log.txt", FILE_MAX_SIZE, buffer, chars_written);
#ifdef WIN32
Sleep(100); // 毫秒
#else
usleep(100 * 1000); // 毫秒
#endif
} else {
// Handle snprintf failure
// Maybe log an error or take appropriate action
}
}
return 0;
}
这篇博客介绍了一个C语言编写的日志模块,旨在不改变原有模块编译方式的前提下,添加对Windows和Linux的支持,同时兼容x86和ARM架构。该模块能记录带有毫秒级时间戳的日志,并在文件大小超过设定限制时自动删除旧文件。测试代码展示了如何向日志文件写入内容并间隔一定时间写入新的日志。

1373

被折叠的 条评论
为什么被折叠?



