如何在C语言中将含空格的CSV文件读取到结构体中?
解决CSV文件中含空格字段的C语言结构体解析问题
要将逗号分隔的文本文件读取到C结构体中,但书名、作者名这类含空格的字段无法用fscanf正常解析——因为fscanf("%s")会在空白字符处截断内容,导致读取的数据完全错乱。
文本文件内容
9780136019701,An Introduction to Organic Chemistry,Timberlake Karen,10,3.54,12-2008
9781506304212,Mathematics for Social Scientists,Kropko Jonathan,7,4.73,12-2015
原代码核心问题
fscanf("%s")无法读取带空格的字段,会把空格后的内容错误识别为下一个字段Book结构体中price定义为int,与文件中的浮点数类型不匹配while(!feof(ptr))作为循环条件会导致最后一次循环读取无效数据- 日期解析逻辑混乱,无法正确获取格式为
MM-YYYY的日期值
解决方案
- 逐行读取完整记录:用
fgets读取整行内容,确保不丢失含空格的字段 - 按逗号分割字段:使用
strtok以逗号为分隔符拆分每个字段,支持含空格的内容 - 修正类型匹配:将
Book结构体的price改为float,匹配文件中的浮点数 - 正确解析日期:拆分日期字段后,用
sscanf提取月份和年份 - 优化循环与内存:用
fgets返回值判断循环结束,初始分配内存并按需扩容,避免频繁realloc
修改后的完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct Date { int year; int month; } Date; typedef struct Book { long long int isbn; char title[100]; char author[100]; int quantity; float price; // 修正为float类型,匹配文件中的浮点数 Date date; } Book; int main() { Book* books = NULL; int n_books = 0; int capacity = 2; // 初始分配容量,减少realloc调用次数 char line[256]; // 存储单行记录,长度足够容纳一条完整数据 FILE *ptr = fopen("Books.txt", "r"); if (ptr == NULL) { printf("无法加载图书数据\n"); exit(EXIT_FAILURE); } // 初始内存分配 books = malloc(sizeof(Book) * capacity); if (books == NULL) { printf("内存分配失败\n"); fclose(ptr); exit(EXIT_FAILURE); } // 逐行读取文件,直到文件结束 while (fgets(line, sizeof(line), ptr) != NULL) { // 内存扩容:当前记录数达到容量时,翻倍扩容 if (n_books >= capacity) { capacity *= 2; Book* temp = realloc(books, sizeof(Book) * capacity); if (temp == NULL) { printf("内存扩容失败\n"); free(books); fclose(ptr); exit(EXIT_FAILURE); } books = temp; } Book* current_book = &books[n_books]; // 按逗号拆分字段 char* token = strtok(line, ","); if (token == NULL) continue; sscanf(token, "%lld", ¤t_book->isbn); // 读取书名,安全复制避免溢出 token = strtok(NULL, ","); if (token == NULL) continue; strncpy(current_book->title, token, sizeof(current_book->title) - 1); current_book->title[sizeof(current_book->title) - 1] = '\0'; // 读取作者 token = strtok(NULL, ","); if (token == NULL) continue; strncpy(current_book->author, token, sizeof(current_book->author) - 1); current_book->author[sizeof(current_book->author) - 1] = '\0'; // 读取库存数量 token = strtok(NULL, ","); if (token == NULL) continue; sscanf(token, "%d", ¤t_book->quantity); // 读取价格 token = strtok(NULL, ","); if (token == NULL) continue; sscanf(token, "%f", ¤t_book->price); // 读取日期,先移除换行符再拆分 token = strtok(NULL, ","); if (token == NULL) continue; size_t len = strlen(token); if (len > 0 && token[len-1] == '\n') { token[len-1] = '\0'; } sscanf(token, "%d-%d", ¤t_book->date.month, ¤t_book->date.year); // 打印验证结果 printf("书名:%s\n", current_book->title); printf("ISBN:%lld\n", current_book->isbn); printf("价格:%.2f\n", current_book->price); printf("出版日期:%d-%d\n", current_book->date.month, current_book->date.year); printf("库存:%d\n", current_book->quantity); printf("作者:%s\n\n", current_book->author); n_books++; } fclose(ptr); free(books); return EXIT_SUCCESS; }
关键说明
fgets读取整行:确保每条记录的所有字段被完整捕获,不受空格干扰strtok分割字段:以逗号为分隔符,精准提取每个字段,支持含空格的内容- 安全字符串复制:用
strncpy替代strcpy,手动添加终止符避免缓冲区溢出 - 内存安全检查:每次内存分配/扩容后都检查是否成功,避免内存泄漏或崩溃
内容的提问来源于stack exchange,提问作者abdelrahman amr
相关产品推荐
相关产品推荐

