Wan2.2-T2V-A5B编程教学C语言文件操作实现视频生成日志记录系统1. 引言如果你刚开始学C语言是不是觉得文件操作那一块儿有点枯燥fopen、fwrite、fclose这些函数光看课本例子总觉得离实际应用很远。今天咱们换个玩法不写那些“学生信息管理系统”了我们来点更酷的。想象一下你写了一个程序能调用一个很厉害的AI模型比如Wan2.2-T2V-A5B输入一段文字描述它就能给你生成一段视频。这本身就很炫酷了对吧但作为一个严谨的开发者你肯定想知道我每次请求生成视频时具体传了什么参数什么时候请求的成功了吗生成的视频存哪儿了这时候C语言的文件操作就派上大用场了。这个教程就是带你用C语言亲手搭建一个“视频生成日志记录系统”。你不仅能学会怎么调用一个AI视频生成服务的API更重要的是你会掌握如何用C语言把每一次操作的“足迹”都清清楚楚、规规矩矩地记录到本地的日志文件里。这就像给你的程序装了一个“黑匣子”出了问题随时可以翻看记录方便分析和调试。学完这个你收获的不仅仅是一段能跑通的代码而是一个完整的、有实际应用场景的编程思维。你会发现原来课本上的fopen和fwrite用对了地方能发挥这么大的作用。2. 项目目标与环境准备2.1 我们要做什么简单说我们要写一个C程序它主要干两件事调用视频生成API根据我们输入的文本描述向Wan2.2-T2V-A5B模型发起请求让它生成一段视频并把生成的视频文件保存到我们电脑上。记录详细日志在发起请求前、收到响应后把整个过程中的关键信息比如请求参数、时间、结果状态、文件保存路径等用特定的格式写入到一个本地的文本文件日志文件里。最终每次运行程序你不仅会得到一个AI生成的视频文件还会在日志文件里看到一行清晰的记录就像这样[2023-10-27 14:30:25] 请求参数: “一只猫在玩毛线球”。 状态: 成功。 结果文件: ./videos/cat_playing_1730017825.mp42.2 动手前的准备工欲善其事必先利其器。我们需要准备好下面几样东西C语言开发环境这个是最基础的。你可以用任何你熟悉的比如Visual StudioWindows、XcodemacOS或者GCCLinux/macOS。确保你的编译器能正常工作。网络请求库C语言标准库本身没有直接发HTTP请求的功能我们需要借助第三方库。这里推荐使用libcurl它是一个非常强大且易用的开源网络传输库。你需要先把它安装到你的系统上。Ubuntu/Debian:sudo apt-get install libcurl4-openssl-devmacOS (使用Homebrew):brew install curlWindows: 可以去 curl官网 下载编译好的库或者使用vcpkg等包管理器安装。JSON解析库API的请求和返回的数据通常都是JSON格式的。C语言处理JSON有点麻烦所以我们用cJSON这个轻量级的库来帮忙。它只有一个.c和一个.h文件集成起来非常方便。你可以从它的 GitHub仓库 下载cJSON.c和cJSON.h文件直接放到你的项目里。Wan2.2-T2V-A5B的API访问权限你需要知道这个AI视频生成服务的API端点URL、以及如何进行认证比如API Key。这部分信息通常需要你在对应的AI服务平台注册账号并创建应用来获取。本教程会假设你已经有了一个可用的API Key和基础URL。把上面这些准备好我们的“舞台”就搭好了接下来可以正式开始写代码了。3. 核心代码实现我们的程序会分成几个模块来写这样结构清晰也方便你理解。我们主要关注两个核心部分日志记录模块和API调用模块。3.1 第一步设计并实现日志记录模块这是本次教学的重点我们用纯C语言的文件操作函数来实现。首先我们创建一个名为logger.h的头文件来定义日志相关的函数。// logger.h #ifndef LOGGER_H #define LOGGER_H #include time.h // 定义一个日志级别枚举方便区分不同类型的日志 typedef enum { LOG_INFO, // 普通信息 LOG_WARNING, // 警告 LOG_ERROR // 错误 } LogLevel; // 初始化日志系统传入日志文件路径 int logger_init(const char* log_file_path); // 写入一条日志 // level: 日志级别 // module: 产生日志的模块名如 API_CALLER // message: 具体的日志信息 void logger_write(LogLevel level, const char* module, const char* message); // 关闭日志系统释放资源 void logger_close(void); #endif // LOGGER_H接下来实现logger.c。这里你会看到fopen,fprintf,fclose等函数的具体应用。// logger.c #include stdio.h #include stdlib.h #include string.h #include “logger.h” static FILE* log_file NULL; int logger_init(const char* log_file_path) { // 使用 “a” 模式打开文件表示追加写入。如果文件不存在则创建它。 log_file fopen(log_file_path, “a”); if (log_file NULL) { // 如果连日志文件都打不开那问题就大了我们只能打印到标准错误输出。 fprintf(stderr, “严重错误无法打开日志文件 %s\n”, log_file_path); return -1; // 返回错误码 } // 可选在文件开头写入一个日志开始的标记 fprintf(log_file, “ 视频生成日志系统启动 \n”); fflush(log_file); // 立即将缓冲区内容写入文件防止程序崩溃丢失日志 return 0; // 初始化成功 } void logger_write(LogLevel level, const char* module, const char* message) { if (log_file NULL) { // 日志系统未初始化直接返回 return; } // 获取当前时间 time_t now; time(now); struct tm* local_time localtime(now); char time_str[64]; strftime(time_str, sizeof(time_str), “%Y-%m-%d %H:%M:%S”, local_time); // 根据日志级别决定在文件里用什么前缀 const char* level_str; switch (level) { case LOG_INFO: level_str “[INFO]”; break; case LOG_WARNING: level_str “[WARN]”; break; case LOG_ERROR: level_str “[ERROR]”; break; default: level_str “[UNKN]”; break; } // 将格式化的日志行写入文件 fprintf(log_file, “%s %s [%s] %s\n”, time_str, level_str, module, message); fflush(log_file); // 同样立即写入确保日志不丢失 // 同时也可以打印到控制台方便调试 printf(“%s %s [%s] %s\n”, time_str, level_str, module, message); } void logger_close(void) { if (log_file ! NULL) { fprintf(log_file, “ 视频生成日志系统关闭 \n\n”); fclose(log_file); log_file NULL; } }这个模块虽然代码不多但涵盖了文件操作的核心打开、写入、关闭。fprintf函数让我们能像printf向屏幕输出一样向文件输出格式化的字符串非常方便。3.2 第二步实现API调用与视频下载现在我们创建一个api_caller.c文件来处理网络请求。这里会用到 libcurl 和 cJSON。为了简化我们假设API的请求体是一个简单的JSON包含prompt文本描述和config一些配置返回的JSON里包含一个video_url字段指向生成好的视频文件。// api_caller.h #ifndef API_CALLER_H #define API_CALLER_H // 调用生成视频API并将视频下载到指定路径 // prompt: 文本描述 // output_video_path: 视频保存的本地路径 // api_key: 你的API密钥 // 返回: 0成功非0失败 int generate_video(const char* prompt, const char* output_video_path, const char* api_key); #endif // API_CALLER_H// api_caller.c #include stdio.h #include stdlib.h #include string.h #include curl/curl.h #include “cJSON.h” #include “logger.h” // 假设的API基础URL请替换为实际地址 #define API_BASE_URL “https://api.example.com/v1/video/generate” // 一个辅助函数用于处理libcurl返回的数据将其存储到内存中 typedef struct { char* data; size_t size; } MemoryStruct; static size_t write_callback(void* contents, size_t size, size_t nmemb, void* userp) { size_t realsize size * nmemb; MemoryStruct* mem (MemoryStruct*)userp; char* ptr realloc(mem-data, mem-size realsize 1); if (!ptr) { logger_write(LOG_ERROR, “API_CALLER”, “内存分配失败 (write_callback)”); return 0; } mem-data ptr; memcpy((mem-data[mem-size]), contents, realsize); mem-size realsize; mem-data[mem-size] 0; // 添加字符串结束符 return realsize; } // 另一个辅助函数用于将视频数据直接写入文件 static size_t write_data_to_file(void* ptr, size_t size, size_t nmemb, FILE* stream) { size_t written fwrite(ptr, size, nmemb, stream); return written; } int generate_video(const char* prompt, const char* output_video_path, const char* api_key) { CURL* curl; CURLcode res; int ret_code 0; // 默认成功 logger_write(LOG_INFO, “API_CALLER”, “开始视频生成请求...”); char log_msg[512]; snprintf(log_msg, sizeof(log_msg), “请求参数: prompt‘%s’, 输出路径‘%s’”, prompt, output_video_path); logger_write(LOG_INFO, “API_CALLER”, log_msg); // 1. 构建JSON请求体 cJSON* request_json cJSON_CreateObject(); cJSON_AddStringToObject(request_json, “prompt”, prompt); cJSON* config cJSON_CreateObject(); cJSON_AddStringToObject(config, “model”, “wan2.2-t2v-a5b”); cJSON_AddNumberToObject(config, “duration”, 5); // 假设生成5秒视频 cJSON_AddItemToObject(request_json, “config”, config); char* request_body cJSON_Print(request_json); cJSON_Delete(request_json); // 2. 初始化libcurl curl_global_init(CURL_GLOBAL_DEFAULT); curl curl_easy_init(); if (curl) { MemoryStruct chunk; chunk.data malloc(1); chunk.size 0; struct curl_slist* headers NULL; headers curl_slist_append(headers, “Content-Type: application/json”); char auth_header[256]; snprintf(auth_header, sizeof(auth_header), “Authorization: Bearer %s”, api_key); headers curl_slist_append(headers, auth_header); curl_easy_setopt(curl, CURLOPT_URL, API_BASE_URL); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request_body); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)chunk); // 3. 执行API调用 res curl_easy_perform(curl); if (res ! CURLE_OK) { logger_write(LOG_ERROR, “API_CALLER”, curl_easy_strerror(res)); ret_code -1; } else { long http_code 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, http_code); snprintf(log_msg, sizeof(log_msg), “API响应状态码: %ld”, http_code); logger_write(LOG_INFO, “API_CALLER”, log_msg); if (http_code 200) { // 4. 解析返回的JSON获取视频URL cJSON* response_json cJSON_Parse(chunk.data); if (response_json) { cJSON* video_url_json cJSON_GetObjectItem(response_json, “video_url”); if (cJSON_IsString(video_url_json) (video_url_json-valuestring ! NULL)) { const char* video_url video_url_json-valuestring; logger_write(LOG_INFO, “API_CALLER”, “解析到视频URL开始下载...”); // 5. 下载视频文件 FILE* fp fopen(output_video_path, “wb”); if (fp) { CURL* curl_dl curl_easy_init(); if (curl_dl) { curl_easy_setopt(curl_dl, CURLOPT_URL, video_url); curl_easy_setopt(curl_dl, CURLOPT_WRITEFUNCTION, write_data_to_file); curl_easy_setopt(curl_dl, CURLOPT_WRITEDATA, fp); curl_easy_perform(curl_dl); curl_easy_cleanup(curl_dl); logger_write(LOG_INFO, “API_CALLER”, “视频文件下载完成。”); } fclose(fp); } else { logger_write(LOG_ERROR, “API_CALLER”, “无法创建本地视频文件。”); ret_code -3; } } else { logger_write(LOG_ERROR, “API_CALLER”, “响应JSON中未找到有效的video_url字段。”); ret_code -2; } cJSON_Delete(response_json); } else { logger_write(LOG_ERROR, “API_CALLER”, “解析API响应JSON失败。”); ret_code -2; } } else { logger_write(LOG_ERROR, “API_CALLER”, “API请求未成功。”); logger_write(LOG_INFO, “API_CALLER”, chunk.data); // 打印错误信息 ret_code -1; } } // 清理 curl_easy_cleanup(curl); curl_slist_free_all(headers); free(chunk.data); } else { logger_write(LOG_ERROR, “API_CALLER”, “初始化libcurl失败。”); ret_code -1; } free(request_body); curl_global_cleanup(); if (ret_code 0) { logger_write(LOG_INFO, “API_CALLER”, “视频生成任务完成。”); } else { logger_write(LOG_ERROR, “API_CALLER”, “视频生成任务失败。”); } return ret_code; }这段代码看起来长但逻辑是清晰的准备请求 - 发送请求 - 处理响应 - 下载文件。每一个关键步骤我们都通过logger_write函数记录了日志。3.3 第三步编写主程序把它们组合起来最后我们写一个main.c把日志模块和API调用模块串联起来形成一个完整的程序。// main.c #include stdio.h #include stdlib.h #include “logger.h” #include “api_caller.h” int main(int argc, char* argv[]) { const char* log_file “video_generation.log”; const char* api_key “YOUR_ACTUAL_API_KEY_HERE”; // 请务必替换成你的真实API Key const char* prompt “一只可爱的熊猫在竹林里吃竹子”; const char* output_path “./generated_panda.mp4”; // 1. 初始化日志系统 if (logger_init(log_file) ! 0) { fprintf(stderr, “日志系统初始化失败程序退出。\n”); return EXIT_FAILURE; } logger_write(LOG_INFO, “MAIN”, “程序启动。”); // 2. 记录本次任务开始 char start_msg[256]; snprintf(start_msg, sizeof(start_msg), “开始处理视频生成任务Prompt: ‘%s’”, prompt); logger_write(LOG_INFO, “MAIN”, start_msg); // 3. 调用视频生成函数 int result generate_video(prompt, output_path, api_key); // 4. 记录最终结果 if (result 0) { logger_write(LOG_INFO, “MAIN”, “视频生成任务执行成功。”); printf(“恭喜视频已生成并保存至: %s\n”, output_path); printf(“详细日志请查看: %s\n”, log_file); } else { logger_write(LOG_ERROR, “MAIN”, “视频生成任务执行失败。”); fprintf(stderr, “任务失败请检查日志文件 %s 获取详细信息。\n”, log_file); } // 5. 关闭日志系统 logger_close(); return (result 0) ? EXIT_SUCCESS : EXIT_FAILURE; }4. 编译、运行与结果查看4.1 如何编译假设你的项目目录结构如下your_project/ ├── cJSON.c ├── cJSON.h ├── logger.h ├── logger.c ├── api_caller.h ├── api_caller.c └── main.c打开终端进入项目目录使用gcc编译记得链接 libcurl 和数学库cJSON可能用到gcc -o video_logger main.c logger.c api_caller.c cJSON.c -lcurl -lm如果一切顺利你会得到一个名为video_loggerLinux/macOS或video_logger.exeWindows的可执行文件。4.2 运行程序在运行前请务必用你从AI服务商那里获取的真实API Key替换main.c中的YOUR_ACTUAL_API_KEY_HERE。然后在终端运行./video_logger程序会开始执行。你会在终端看到日志输出同时所有日志也会被写入到video_generation.log文件中。4.3 查看日志文件程序运行结束后用文本编辑器打开video_generation.log文件你会看到类似下面的内容 视频生成日志系统启动 2023-10-27 15:45:10 [INFO] [MAIN] 程序启动。 2023-10-27 15:45:10 [INFO] [MAIN] 开始处理视频生成任务Prompt: ‘一只可爱的熊猫在竹林里吃竹子’ 2023-10-27 15:45:10 [INFO] [API_CALLER] 开始视频生成请求... 2023-10-27 15:45:10 [INFO] [API_CALLER] 请求参数: prompt‘一只可爱的熊猫在竹林里吃竹子’ 输出路径‘./generated_panda.mp4’ 2023-10-27 15:45:12 [INFO] [API_CALLER] API响应状态码: 200 2023-10-27 15:45:12 [INFO] [API_CALLER] 解析到视频URL开始下载... 2023-10-27 15:45:15 [INFO] [API_CALLER] 视频文件下载完成。 2023-10-27 15:45:15 [INFO] [API_CALLER] 视频生成任务完成。 2023-10-27 15:45:15 [INFO] [MAIN] 视频生成任务执行成功。 视频生成日志系统关闭 看每一次请求的时间、动作、状态、甚至关键参数都被完整地记录了下来。这就是日志系统的威力5. 总结走完这个完整的项目我希望你收获的不只是几行关于fopen和fwrite的代码。更重要的是你看到了如何将C语言的基础知识文件I/O、字符串处理、结构体和第三方库libcurl, cJSON结合起来去解决一个真实的、有趣的问题。这个“视频生成日志记录系统”虽然简单但已经具备了核心骨架。你可以在此基础上做很多扩展比如日志分级我们已经做了可以更精细地控制哪些日志要写哪些不要。日志轮转防止单个日志文件过大可以按日期或大小切分文件。更丰富的上下文在日志里记录线程ID、用户ID等信息便于在复杂系统中排查问题。错误处理增强对网络超时、磁盘满等异常情况进行更健壮的处理和记录。下次当你再看到文件操作的章节时可以想想这个项目。技术本身是工具而项目是让工具发挥价值的场景。试着用你学到的知识去创造一些能解决实际需求的小工具编程的乐趣和成就感往往就来自于此。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。
Wan2.2-T2V-A5B编程教学:C语言文件操作实现视频生成日志记录系统
Wan2.2-T2V-A5B编程教学C语言文件操作实现视频生成日志记录系统1. 引言如果你刚开始学C语言是不是觉得文件操作那一块儿有点枯燥fopen、fwrite、fclose这些函数光看课本例子总觉得离实际应用很远。今天咱们换个玩法不写那些“学生信息管理系统”了我们来点更酷的。想象一下你写了一个程序能调用一个很厉害的AI模型比如Wan2.2-T2V-A5B输入一段文字描述它就能给你生成一段视频。这本身就很炫酷了对吧但作为一个严谨的开发者你肯定想知道我每次请求生成视频时具体传了什么参数什么时候请求的成功了吗生成的视频存哪儿了这时候C语言的文件操作就派上大用场了。这个教程就是带你用C语言亲手搭建一个“视频生成日志记录系统”。你不仅能学会怎么调用一个AI视频生成服务的API更重要的是你会掌握如何用C语言把每一次操作的“足迹”都清清楚楚、规规矩矩地记录到本地的日志文件里。这就像给你的程序装了一个“黑匣子”出了问题随时可以翻看记录方便分析和调试。学完这个你收获的不仅仅是一段能跑通的代码而是一个完整的、有实际应用场景的编程思维。你会发现原来课本上的fopen和fwrite用对了地方能发挥这么大的作用。2. 项目目标与环境准备2.1 我们要做什么简单说我们要写一个C程序它主要干两件事调用视频生成API根据我们输入的文本描述向Wan2.2-T2V-A5B模型发起请求让它生成一段视频并把生成的视频文件保存到我们电脑上。记录详细日志在发起请求前、收到响应后把整个过程中的关键信息比如请求参数、时间、结果状态、文件保存路径等用特定的格式写入到一个本地的文本文件日志文件里。最终每次运行程序你不仅会得到一个AI生成的视频文件还会在日志文件里看到一行清晰的记录就像这样[2023-10-27 14:30:25] 请求参数: “一只猫在玩毛线球”。 状态: 成功。 结果文件: ./videos/cat_playing_1730017825.mp42.2 动手前的准备工欲善其事必先利其器。我们需要准备好下面几样东西C语言开发环境这个是最基础的。你可以用任何你熟悉的比如Visual StudioWindows、XcodemacOS或者GCCLinux/macOS。确保你的编译器能正常工作。网络请求库C语言标准库本身没有直接发HTTP请求的功能我们需要借助第三方库。这里推荐使用libcurl它是一个非常强大且易用的开源网络传输库。你需要先把它安装到你的系统上。Ubuntu/Debian:sudo apt-get install libcurl4-openssl-devmacOS (使用Homebrew):brew install curlWindows: 可以去 curl官网 下载编译好的库或者使用vcpkg等包管理器安装。JSON解析库API的请求和返回的数据通常都是JSON格式的。C语言处理JSON有点麻烦所以我们用cJSON这个轻量级的库来帮忙。它只有一个.c和一个.h文件集成起来非常方便。你可以从它的 GitHub仓库 下载cJSON.c和cJSON.h文件直接放到你的项目里。Wan2.2-T2V-A5B的API访问权限你需要知道这个AI视频生成服务的API端点URL、以及如何进行认证比如API Key。这部分信息通常需要你在对应的AI服务平台注册账号并创建应用来获取。本教程会假设你已经有了一个可用的API Key和基础URL。把上面这些准备好我们的“舞台”就搭好了接下来可以正式开始写代码了。3. 核心代码实现我们的程序会分成几个模块来写这样结构清晰也方便你理解。我们主要关注两个核心部分日志记录模块和API调用模块。3.1 第一步设计并实现日志记录模块这是本次教学的重点我们用纯C语言的文件操作函数来实现。首先我们创建一个名为logger.h的头文件来定义日志相关的函数。// logger.h #ifndef LOGGER_H #define LOGGER_H #include time.h // 定义一个日志级别枚举方便区分不同类型的日志 typedef enum { LOG_INFO, // 普通信息 LOG_WARNING, // 警告 LOG_ERROR // 错误 } LogLevel; // 初始化日志系统传入日志文件路径 int logger_init(const char* log_file_path); // 写入一条日志 // level: 日志级别 // module: 产生日志的模块名如 API_CALLER // message: 具体的日志信息 void logger_write(LogLevel level, const char* module, const char* message); // 关闭日志系统释放资源 void logger_close(void); #endif // LOGGER_H接下来实现logger.c。这里你会看到fopen,fprintf,fclose等函数的具体应用。// logger.c #include stdio.h #include stdlib.h #include string.h #include “logger.h” static FILE* log_file NULL; int logger_init(const char* log_file_path) { // 使用 “a” 模式打开文件表示追加写入。如果文件不存在则创建它。 log_file fopen(log_file_path, “a”); if (log_file NULL) { // 如果连日志文件都打不开那问题就大了我们只能打印到标准错误输出。 fprintf(stderr, “严重错误无法打开日志文件 %s\n”, log_file_path); return -1; // 返回错误码 } // 可选在文件开头写入一个日志开始的标记 fprintf(log_file, “ 视频生成日志系统启动 \n”); fflush(log_file); // 立即将缓冲区内容写入文件防止程序崩溃丢失日志 return 0; // 初始化成功 } void logger_write(LogLevel level, const char* module, const char* message) { if (log_file NULL) { // 日志系统未初始化直接返回 return; } // 获取当前时间 time_t now; time(now); struct tm* local_time localtime(now); char time_str[64]; strftime(time_str, sizeof(time_str), “%Y-%m-%d %H:%M:%S”, local_time); // 根据日志级别决定在文件里用什么前缀 const char* level_str; switch (level) { case LOG_INFO: level_str “[INFO]”; break; case LOG_WARNING: level_str “[WARN]”; break; case LOG_ERROR: level_str “[ERROR]”; break; default: level_str “[UNKN]”; break; } // 将格式化的日志行写入文件 fprintf(log_file, “%s %s [%s] %s\n”, time_str, level_str, module, message); fflush(log_file); // 同样立即写入确保日志不丢失 // 同时也可以打印到控制台方便调试 printf(“%s %s [%s] %s\n”, time_str, level_str, module, message); } void logger_close(void) { if (log_file ! NULL) { fprintf(log_file, “ 视频生成日志系统关闭 \n\n”); fclose(log_file); log_file NULL; } }这个模块虽然代码不多但涵盖了文件操作的核心打开、写入、关闭。fprintf函数让我们能像printf向屏幕输出一样向文件输出格式化的字符串非常方便。3.2 第二步实现API调用与视频下载现在我们创建一个api_caller.c文件来处理网络请求。这里会用到 libcurl 和 cJSON。为了简化我们假设API的请求体是一个简单的JSON包含prompt文本描述和config一些配置返回的JSON里包含一个video_url字段指向生成好的视频文件。// api_caller.h #ifndef API_CALLER_H #define API_CALLER_H // 调用生成视频API并将视频下载到指定路径 // prompt: 文本描述 // output_video_path: 视频保存的本地路径 // api_key: 你的API密钥 // 返回: 0成功非0失败 int generate_video(const char* prompt, const char* output_video_path, const char* api_key); #endif // API_CALLER_H// api_caller.c #include stdio.h #include stdlib.h #include string.h #include curl/curl.h #include “cJSON.h” #include “logger.h” // 假设的API基础URL请替换为实际地址 #define API_BASE_URL “https://api.example.com/v1/video/generate” // 一个辅助函数用于处理libcurl返回的数据将其存储到内存中 typedef struct { char* data; size_t size; } MemoryStruct; static size_t write_callback(void* contents, size_t size, size_t nmemb, void* userp) { size_t realsize size * nmemb; MemoryStruct* mem (MemoryStruct*)userp; char* ptr realloc(mem-data, mem-size realsize 1); if (!ptr) { logger_write(LOG_ERROR, “API_CALLER”, “内存分配失败 (write_callback)”); return 0; } mem-data ptr; memcpy((mem-data[mem-size]), contents, realsize); mem-size realsize; mem-data[mem-size] 0; // 添加字符串结束符 return realsize; } // 另一个辅助函数用于将视频数据直接写入文件 static size_t write_data_to_file(void* ptr, size_t size, size_t nmemb, FILE* stream) { size_t written fwrite(ptr, size, nmemb, stream); return written; } int generate_video(const char* prompt, const char* output_video_path, const char* api_key) { CURL* curl; CURLcode res; int ret_code 0; // 默认成功 logger_write(LOG_INFO, “API_CALLER”, “开始视频生成请求...”); char log_msg[512]; snprintf(log_msg, sizeof(log_msg), “请求参数: prompt‘%s’, 输出路径‘%s’”, prompt, output_video_path); logger_write(LOG_INFO, “API_CALLER”, log_msg); // 1. 构建JSON请求体 cJSON* request_json cJSON_CreateObject(); cJSON_AddStringToObject(request_json, “prompt”, prompt); cJSON* config cJSON_CreateObject(); cJSON_AddStringToObject(config, “model”, “wan2.2-t2v-a5b”); cJSON_AddNumberToObject(config, “duration”, 5); // 假设生成5秒视频 cJSON_AddItemToObject(request_json, “config”, config); char* request_body cJSON_Print(request_json); cJSON_Delete(request_json); // 2. 初始化libcurl curl_global_init(CURL_GLOBAL_DEFAULT); curl curl_easy_init(); if (curl) { MemoryStruct chunk; chunk.data malloc(1); chunk.size 0; struct curl_slist* headers NULL; headers curl_slist_append(headers, “Content-Type: application/json”); char auth_header[256]; snprintf(auth_header, sizeof(auth_header), “Authorization: Bearer %s”, api_key); headers curl_slist_append(headers, auth_header); curl_easy_setopt(curl, CURLOPT_URL, API_BASE_URL); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request_body); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)chunk); // 3. 执行API调用 res curl_easy_perform(curl); if (res ! CURLE_OK) { logger_write(LOG_ERROR, “API_CALLER”, curl_easy_strerror(res)); ret_code -1; } else { long http_code 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, http_code); snprintf(log_msg, sizeof(log_msg), “API响应状态码: %ld”, http_code); logger_write(LOG_INFO, “API_CALLER”, log_msg); if (http_code 200) { // 4. 解析返回的JSON获取视频URL cJSON* response_json cJSON_Parse(chunk.data); if (response_json) { cJSON* video_url_json cJSON_GetObjectItem(response_json, “video_url”); if (cJSON_IsString(video_url_json) (video_url_json-valuestring ! NULL)) { const char* video_url video_url_json-valuestring; logger_write(LOG_INFO, “API_CALLER”, “解析到视频URL开始下载...”); // 5. 下载视频文件 FILE* fp fopen(output_video_path, “wb”); if (fp) { CURL* curl_dl curl_easy_init(); if (curl_dl) { curl_easy_setopt(curl_dl, CURLOPT_URL, video_url); curl_easy_setopt(curl_dl, CURLOPT_WRITEFUNCTION, write_data_to_file); curl_easy_setopt(curl_dl, CURLOPT_WRITEDATA, fp); curl_easy_perform(curl_dl); curl_easy_cleanup(curl_dl); logger_write(LOG_INFO, “API_CALLER”, “视频文件下载完成。”); } fclose(fp); } else { logger_write(LOG_ERROR, “API_CALLER”, “无法创建本地视频文件。”); ret_code -3; } } else { logger_write(LOG_ERROR, “API_CALLER”, “响应JSON中未找到有效的video_url字段。”); ret_code -2; } cJSON_Delete(response_json); } else { logger_write(LOG_ERROR, “API_CALLER”, “解析API响应JSON失败。”); ret_code -2; } } else { logger_write(LOG_ERROR, “API_CALLER”, “API请求未成功。”); logger_write(LOG_INFO, “API_CALLER”, chunk.data); // 打印错误信息 ret_code -1; } } // 清理 curl_easy_cleanup(curl); curl_slist_free_all(headers); free(chunk.data); } else { logger_write(LOG_ERROR, “API_CALLER”, “初始化libcurl失败。”); ret_code -1; } free(request_body); curl_global_cleanup(); if (ret_code 0) { logger_write(LOG_INFO, “API_CALLER”, “视频生成任务完成。”); } else { logger_write(LOG_ERROR, “API_CALLER”, “视频生成任务失败。”); } return ret_code; }这段代码看起来长但逻辑是清晰的准备请求 - 发送请求 - 处理响应 - 下载文件。每一个关键步骤我们都通过logger_write函数记录了日志。3.3 第三步编写主程序把它们组合起来最后我们写一个main.c把日志模块和API调用模块串联起来形成一个完整的程序。// main.c #include stdio.h #include stdlib.h #include “logger.h” #include “api_caller.h” int main(int argc, char* argv[]) { const char* log_file “video_generation.log”; const char* api_key “YOUR_ACTUAL_API_KEY_HERE”; // 请务必替换成你的真实API Key const char* prompt “一只可爱的熊猫在竹林里吃竹子”; const char* output_path “./generated_panda.mp4”; // 1. 初始化日志系统 if (logger_init(log_file) ! 0) { fprintf(stderr, “日志系统初始化失败程序退出。\n”); return EXIT_FAILURE; } logger_write(LOG_INFO, “MAIN”, “程序启动。”); // 2. 记录本次任务开始 char start_msg[256]; snprintf(start_msg, sizeof(start_msg), “开始处理视频生成任务Prompt: ‘%s’”, prompt); logger_write(LOG_INFO, “MAIN”, start_msg); // 3. 调用视频生成函数 int result generate_video(prompt, output_path, api_key); // 4. 记录最终结果 if (result 0) { logger_write(LOG_INFO, “MAIN”, “视频生成任务执行成功。”); printf(“恭喜视频已生成并保存至: %s\n”, output_path); printf(“详细日志请查看: %s\n”, log_file); } else { logger_write(LOG_ERROR, “MAIN”, “视频生成任务执行失败。”); fprintf(stderr, “任务失败请检查日志文件 %s 获取详细信息。\n”, log_file); } // 5. 关闭日志系统 logger_close(); return (result 0) ? EXIT_SUCCESS : EXIT_FAILURE; }4. 编译、运行与结果查看4.1 如何编译假设你的项目目录结构如下your_project/ ├── cJSON.c ├── cJSON.h ├── logger.h ├── logger.c ├── api_caller.h ├── api_caller.c └── main.c打开终端进入项目目录使用gcc编译记得链接 libcurl 和数学库cJSON可能用到gcc -o video_logger main.c logger.c api_caller.c cJSON.c -lcurl -lm如果一切顺利你会得到一个名为video_loggerLinux/macOS或video_logger.exeWindows的可执行文件。4.2 运行程序在运行前请务必用你从AI服务商那里获取的真实API Key替换main.c中的YOUR_ACTUAL_API_KEY_HERE。然后在终端运行./video_logger程序会开始执行。你会在终端看到日志输出同时所有日志也会被写入到video_generation.log文件中。4.3 查看日志文件程序运行结束后用文本编辑器打开video_generation.log文件你会看到类似下面的内容 视频生成日志系统启动 2023-10-27 15:45:10 [INFO] [MAIN] 程序启动。 2023-10-27 15:45:10 [INFO] [MAIN] 开始处理视频生成任务Prompt: ‘一只可爱的熊猫在竹林里吃竹子’ 2023-10-27 15:45:10 [INFO] [API_CALLER] 开始视频生成请求... 2023-10-27 15:45:10 [INFO] [API_CALLER] 请求参数: prompt‘一只可爱的熊猫在竹林里吃竹子’ 输出路径‘./generated_panda.mp4’ 2023-10-27 15:45:12 [INFO] [API_CALLER] API响应状态码: 200 2023-10-27 15:45:12 [INFO] [API_CALLER] 解析到视频URL开始下载... 2023-10-27 15:45:15 [INFO] [API_CALLER] 视频文件下载完成。 2023-10-27 15:45:15 [INFO] [API_CALLER] 视频生成任务完成。 2023-10-27 15:45:15 [INFO] [MAIN] 视频生成任务执行成功。 视频生成日志系统关闭 看每一次请求的时间、动作、状态、甚至关键参数都被完整地记录了下来。这就是日志系统的威力5. 总结走完这个完整的项目我希望你收获的不只是几行关于fopen和fwrite的代码。更重要的是你看到了如何将C语言的基础知识文件I/O、字符串处理、结构体和第三方库libcurl, cJSON结合起来去解决一个真实的、有趣的问题。这个“视频生成日志记录系统”虽然简单但已经具备了核心骨架。你可以在此基础上做很多扩展比如日志分级我们已经做了可以更精细地控制哪些日志要写哪些不要。日志轮转防止单个日志文件过大可以按日期或大小切分文件。更丰富的上下文在日志里记录线程ID、用户ID等信息便于在复杂系统中排查问题。错误处理增强对网络超时、磁盘满等异常情况进行更健壮的处理和记录。下次当你再看到文件操作的章节时可以想想这个项目。技术本身是工具而项目是让工具发挥价值的场景。试着用你学到的知识去创造一些能解决实际需求的小工具编程的乐趣和成就感往往就来自于此。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。