从 csv 文件中读取,分隔 C 中的每一行和每个字段
Read from a csv file , separate every line and every field in C
我有一个 csv 文件,我必须在其中分隔该行中的每一行 (\n) 和每个字段 (,)。
我的目标是创建一个结构数组。数组的每个“框”中的每个结构必须包含每一行的 4 个字段。
我怎么能用c写呢?
我想使用 fscanf 和 fgets,但我不知道如何一起使用它们,因为使用 fgets 我想分割线,而使用 fscanf 我想分割字段。
最终情况:
| 0 , noto, 233460, 32209.073312 | 1, piangea, 4741192, 811.. | 2 ,spenti! , .... |
| position 0 in the array | position 1 in the array | position 2 in the array |
records.csv
0,诺托,233460,32209.073312
1,piangea,4741192,81176.622633
2,花!,1014671, 4476.013614
3,misericordia,496325,61628.929334
4,全多,4476757,10838.641053
main.c
#include <stdlib.h>
#include<stdio.h>
#include <string.h>
struct _SortedArray {
int id;
char field1[12];
int field2;
float field3;
};
int main() {
FILE *fd;
int res;
struct _SortedArray files[101];
int n;
fd = fopen("records.csv", "r");
if (fd == NULL) {
perror("Error");
exit(1);
}
char r[100];
n = 0;
while (n<6) {
if(fgets(r,100,fd)!=NULL){
puts(r);
fscanf(r, "%[^,],%[^,],%[^,],%[^\n]\n", &files[n].id, &files[n].field1, &files[n].field2, &files[n].field3);
}
n++;
}
for(int i=0;i<6;i++){
printf(" INT:%c,CHAR:%s //",files[i].id, files[i].field1);
}
return 0;
}
您的代码包含各种小问题和主要不一致之处。主要的不一致是您应该使用 sscanf
而不是 fscanf
来处理 fgets
.
返回的行
但这还不是全部:
- misericordia 有 12 个字符。由于 C 字符串需要 NULL 终止符,因此
field1
的大小必须至少为 13
- 格式字符要与字段类型一致
- 当您读入一个 char 数组时,该数组会衰减为一个指针:您不能添加
&
所以该行可以变成:
sscanf(r, "%d,%[^,],%d,%f", &files[n].id, files[n].field1, &files[n].field2, &files[n].field3)
其他可能的改进:
- 以
_
开头的标识符应保留给您不使用的标识符。接近一个意见,但在这里你最好使用 SortedArray
- 尽可能用
sizeof
运算符替换大小的普通 魔法值 。如果您稍后更改大小,则必须在代码中的一个位置进行更改(最佳做法:不要重复自己)
- 控制输入函数的结果(这里
[s]scanf
对错误的输入数据具有鲁棒性
- 最终控制行尾不留任何内容
- 只尝试打印尽可能多的行
- 删除未使用的变量(一个好的编译器应该发出警告)
- 始终将字符串输入限制为缓冲区的大小 (
%12[^,]
)
代码可以变成:
#include <stdlib.h>
#include<stdio.h>
#include <string.h>
struct SortedArray {
int id;
char field1[13];
int field2;
float field3;
};
int main() {
FILE *fd;
// int res;
struct SortedArray files[101];
int n;
fd = fopen("records.csv", "r");
if (fd == NULL) {
perror("Error");
exit(1);
}
char r[100];
for (n=0; n<sizeof(files)/sizeof(files[0]); n++) {
if(fgets(r,sizeof(r),fd)==NULL){
break;
}
char dummy[2]; // to control nothing is left on end of line
//puts(r);
if (4 != sscanf(r, "%d,%12[^,],%d,%f%1s", &files[n].id, files[n].field1, &files[n].field2, &files[n].field3, dummy)) {
perror("Incorrect line");
fprintf(stderr, "Line %d : %s\n", n+1, r);
}
}
for(int i=0;i<n;i++){
printf(" INT:%d,CHAR:%s //",files[i].id, files[i].field1);
}
return 0;
}
我有一个 csv 文件,我必须在其中分隔该行中的每一行 (\n) 和每个字段 (,)。 我的目标是创建一个结构数组。数组的每个“框”中的每个结构必须包含每一行的 4 个字段。 我怎么能用c写呢? 我想使用 fscanf 和 fgets,但我不知道如何一起使用它们,因为使用 fgets 我想分割线,而使用 fscanf 我想分割字段。
最终情况:
| 0 , noto, 233460, 32209.073312 | 1, piangea, 4741192, 811.. | 2 ,spenti! , .... |
| position 0 in the array | position 1 in the array | position 2 in the array |
records.csv
0,诺托,233460,32209.073312
1,piangea,4741192,81176.622633
2,花!,1014671, 4476.013614
3,misericordia,496325,61628.929334
4,全多,4476757,10838.641053
main.c
#include <stdlib.h>
#include<stdio.h>
#include <string.h>
struct _SortedArray {
int id;
char field1[12];
int field2;
float field3;
};
int main() {
FILE *fd;
int res;
struct _SortedArray files[101];
int n;
fd = fopen("records.csv", "r");
if (fd == NULL) {
perror("Error");
exit(1);
}
char r[100];
n = 0;
while (n<6) {
if(fgets(r,100,fd)!=NULL){
puts(r);
fscanf(r, "%[^,],%[^,],%[^,],%[^\n]\n", &files[n].id, &files[n].field1, &files[n].field2, &files[n].field3);
}
n++;
}
for(int i=0;i<6;i++){
printf(" INT:%c,CHAR:%s //",files[i].id, files[i].field1);
}
return 0;
}
您的代码包含各种小问题和主要不一致之处。主要的不一致是您应该使用 sscanf
而不是 fscanf
来处理 fgets
.
但这还不是全部:
- misericordia 有 12 个字符。由于 C 字符串需要 NULL 终止符,因此
field1
的大小必须至少为 13 - 格式字符要与字段类型一致
- 当您读入一个 char 数组时,该数组会衰减为一个指针:您不能添加
&
所以该行可以变成:
sscanf(r, "%d,%[^,],%d,%f", &files[n].id, files[n].field1, &files[n].field2, &files[n].field3)
其他可能的改进:
- 以
_
开头的标识符应保留给您不使用的标识符。接近一个意见,但在这里你最好使用SortedArray
- 尽可能用
sizeof
运算符替换大小的普通 魔法值 。如果您稍后更改大小,则必须在代码中的一个位置进行更改(最佳做法:不要重复自己) - 控制输入函数的结果(这里
[s]scanf
对错误的输入数据具有鲁棒性 - 最终控制行尾不留任何内容
- 只尝试打印尽可能多的行
- 删除未使用的变量(一个好的编译器应该发出警告)
- 始终将字符串输入限制为缓冲区的大小 (
%12[^,]
)
代码可以变成:
#include <stdlib.h>
#include<stdio.h>
#include <string.h>
struct SortedArray {
int id;
char field1[13];
int field2;
float field3;
};
int main() {
FILE *fd;
// int res;
struct SortedArray files[101];
int n;
fd = fopen("records.csv", "r");
if (fd == NULL) {
perror("Error");
exit(1);
}
char r[100];
for (n=0; n<sizeof(files)/sizeof(files[0]); n++) {
if(fgets(r,sizeof(r),fd)==NULL){
break;
}
char dummy[2]; // to control nothing is left on end of line
//puts(r);
if (4 != sscanf(r, "%d,%12[^,],%d,%f%1s", &files[n].id, files[n].field1, &files[n].field2, &files[n].field3, dummy)) {
perror("Incorrect line");
fprintf(stderr, "Line %d : %s\n", n+1, r);
}
}
for(int i=0;i<n;i++){
printf(" INT:%d,CHAR:%s //",files[i].id, files[i].field1);
}
return 0;
}