概述
本文案例基于一个已有的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;
}