C语言读取CSV文件单条正常多条报错:格式问题排查
CSV文件读取错误排查与修复(C语言场景)
问题现象
使用fscanf读取TXT格式CSV文件时,单条数据可正常读取,包含两条数据时触发File format incorrect.错误。
用户提供的文件内容:
1,Nanggroe Aceh Darussalam,Rumah Sakit,RSU Cut Nyak Dhien,Jl. Tm Bahrum No. 1 Langsa 2,Jawa Barat,Klinik Utama,dr. Sunarhadi,Raya Cikaret No. 12
原读取代码:
do{ read = fscanf(file, "%d,%100[^,],%100[^,],%100[^,],%100[^,]\n", &students[records].no, students[records].prov, students[records].tipe, students[records].nama, students[records].alamat); if (read == 5) records++; if (read != 5 && !feof(file)){ printf("File format incorrect.\n"); return 1; } if (ferror(file)){ printf("Error reading file.\n"); return 1; } } while (!feof(file));
期望输出:
No : 1 Prov : Nanggroe Aceh Darussalam Tipe : Rumah Sakit Nama : RSU Cut Nyak Dhien Alamat : Jl. Tm Bahrum No. 1 Langsa No : 2 Prov : Jawa Barat Tipe : Klinik Utama Nama : dr. Sunarhadi Alamat : Raya Cikaret No. 12
错误原因
- 格式字符串匹配问题:最后一个字段使用
%100[^,]会匹配所有非逗号字符,包括换行符,导致换行符被读入alamat字段。后续的\n格式符虽然会跳过空白,但读取最后一行时,若该行无末尾换行,fscanf尝试匹配\n会触发EOF,导致返回值异常。 - 循环逻辑缺陷:
do...while(!feof(file))的写法会导致文件读完后多执行一次循环,此时fscanf返回EOF,触发read !=5的判断,进而抛出格式错误。
修复方案
改用fgets读取整行后再用sscanf解析,避免直接用fscanf处理跨换行的字段匹配问题,同时修正循环逻辑:
修正后的读取代码
#include <stdio.h> #include <string.h> #define MAX_LINE 512 #define MAX_RECORDS 100 // 根据实际需求调整数组大小 typedef struct { int no; char prov[101]; char tipe[101]; char nama[101]; char alamat[101]; } Student; int main() { FILE *file = fopen("data.txt", "r"); if (!file) { printf("Failed to open file.\n"); return 1; } Student students[MAX_RECORDS]; int records = 0; char line[MAX_LINE]; int read; while (fgets(line, MAX_LINE, file) != NULL) { // 去除行尾的换行符 size_t len = strlen(line); if (len > 0 && line[len-1] == '\n') { line[len-1] = '\0'; } // 解析单行数据 read = sscanf(line, "%d,%100[^,],%100[^,],%100[^,],%100[^,]", &students[records].no, students[records].prov, students[records].tipe, students[records].nama, students[records].alamat); if (read != 5) { printf("File format incorrect at line %d.\n", records + 1); fclose(file); return 1; } records++; if (records >= MAX_RECORDS) { printf("Exceeded maximum record limit.\n"); fclose(file); return 1; } } if (ferror(file)) { printf("Error reading file.\n"); fclose(file); return 1; } fclose(file); // 打印结果 for (int i = 0; i < records; i++) { printf("No : %d\n", students[i].no); printf("Prov : %s\n", students[i].prov); printf("Tipe : %s\n", students[i].tipe); printf("Nama : %s\n", students[i].nama); printf("Alamat : %s\n\n", students[i].alamat); } return 0; }
修复说明
- 整行读取:用
fgets读取完整一行,确保每次处理独立的一条数据,避免换行符干扰字段解析。 - 去除换行符:提前去掉行尾的换行符,让
sscanf可以准确解析到行尾。 - 循环逻辑优化:
while(fgets(...))直接判断是否读取到有效行,避免feof的时机问题。 - 边界检查:增加数组容量检查,防止越界。
测试结果
运行修正后的代码,将输出与用户期望完全一致的内容。
内容的提问来源于stack exchange,提问作者xNapz
相关产品推荐
相关产品推荐

