C语言CSV文件编辑求助:根据城市ID修改气象数据
嘿,作为刚入门编程的新手,处理CSV文件确实容易摸不着头脑——我来一步步帮你拆解这个问题,从提取城市ID到修改天气信息,都给你讲明白!
第一步:从city.csv提取目标城市的ID
CSV本质是纯文本文件,每行用逗号分隔字段,我们可以通过逐行读取+字段分割的方式找到目标城市对应的ID。这里假设你的city.csv格式是城市名,城市ID(比如Beijing,101010100),以下是实现代码:
#include <stdio.h> #include <string.h> #include <stdlib.h> // 根据城市名从city.csv获取对应的ID int get_city_id(const char* target_city, const char* city_file_path) { // 打开city.csv文件(只读模式) FILE* city_fp = fopen(city_file_path, "r"); if (!city_fp) { perror("打开city.csv失败"); // 打印具体错误原因 return -1; // 返回-1表示出错 } char line_buffer[256]; // 存储每行内容的缓冲区 // 如果CSV有表头,先跳过第一行(比如"城市名,城市ID"这行) fgets(line_buffer, sizeof(line_buffer), city_fp); // 逐行读取文件内容 while (fgets(line_buffer, sizeof(line_buffer), city_fp) != NULL) { // 去掉行尾的换行符(避免干扰字符串比较) line_buffer[strcspn(line_buffer, "\n")] = '\0'; // 用逗号分割字段:第一个是城市名,第二个是ID char* city_name = strtok(line_buffer, ","); char* id_str = strtok(NULL, ","); // 检查字段是否有效,并且匹配目标城市 if (city_name && id_str && strcmp(city_name, target_city) == 0) { int city_id = atoi(id_str); // 把字符串ID转成整数 fclose(city_fp); // 关闭文件 return city_id; } } // 遍历完没找到目标城市 printf("未找到目标城市:%s\n", target_city); fclose(city_fp); return -1; }
第二步:根据ID修改meteo.csv的天气信息
直接修改CSV文件中间的内容比较麻烦(会覆盖后续字节),业内常用的方法是:读取原文件所有内容,修改对应行后写入临时文件,最后用临时文件替换原文件。假设你的meteo.csv格式是城市ID,日期,天气(比如101010100,2024-05-20,晴),代码如下:
// 根据城市ID更新meteo.csv中的天气信息 int update_meteo_weather(int target_id, const char* new_weather, const char* meteo_file_path) { // 打开原meteo.csv(只读) FILE* meteo_fp = fopen(meteo_file_path, "r"); if (!meteo_fp) { perror("打开meteo.csv失败"); return -1; } // 创建临时文件(写入模式) FILE* temp_fp = fopen("temp_meteo.csv", "w"); if (!temp_fp) { perror("创建临时文件失败"); fclose(meteo_fp); return -1; } char line_buffer[256]; // 先写入表头(如果有) fgets(line_buffer, sizeof(line_buffer), meteo_fp); fputs(line_buffer, temp_fp); // 逐行处理原文件内容 while (fgets(line_buffer, sizeof(line_buffer), meteo_fp) != NULL) { line_buffer[strcspn(line_buffer, "\n")] = '\0'; // 分割字段:ID、日期、天气 char* id_str = strtok(line_buffer, ","); char* date = strtok(NULL, ","); char* old_weather = strtok(NULL, ","); if (id_str && date && old_weather) { int current_id = atoi(id_str); // 如果匹配目标ID,写入修改后的行 if (current_id == target_id) { fprintf(temp_fp, "%d,%s,%s\n", target_id, date, new_weather); } else { // 不匹配就原样写入 fprintf(temp_fp, "%s,%s,%s\n", id_str, date, old_weather); } } else { // 遇到格式错误的行,原样保留 fputs(line_buffer, temp_fp); fputs("\n", temp_fp); } } // 关闭文件 fclose(meteo_fp); fclose(temp_fp); // 替换原文件:先删除原文件,再把临时文件重命名为原文件名 if (remove(meteo_file_path) != 0) { perror("删除原meteo.csv失败"); remove("temp_meteo.csv"); // 清理临时文件 return -1; } if (rename("temp_meteo.csv", meteo_file_path) != 0) { perror("重命名临时文件失败"); return -1; } printf("天气信息修改成功!\n"); return 0; }
主函数调用示例
把上面两个函数结合起来,就能完成你的需求:
int main() { const char* target_city = "Beijing"; // 你要找的目标城市 const char* new_weather = "多云转晴"; // 新的天气信息 // 第一步:获取城市ID int city_id = get_city_id(target_city, "city.csv"); if (city_id == -1) { return 1; // 获取失败,退出程序 } // 第二步:修改天气信息 if (update_meteo_weather(city_id, new_weather, "meteo.csv") == -1) { return 1; // 修改失败,退出程序 } return 0; }
一些关键注意事项
- CSV格式兼容性:上面的代码假设CSV没有带引号的字段(比如
"New York",101这种带引号的城市名),如果你的CSV有这种情况,strtok会失效,需要手动编写更复杂的字段解析逻辑(比如判断引号内的逗号不分割)。 - 缓冲区大小:示例中用了256字节的缓冲区,如果你的CSV行很长,需要调大缓冲区,或者改用动态内存分配(
malloc)。 - 错误处理:代码里加了大量的错误判断,这在实际项目中非常重要——比如文件打不开、找不到城市、文件操作失败等情况,都要给出明确的提示。
内容的提问来源于stack exchange,提问作者Jessijow Black
相关产品推荐
相关产品推荐

