使用strtok读取csv文件
我正在尝试使用C中的strtok读取csv文件,并将内容存储到struct Game的数组中。 我的代码如下所示:使用strtok读取csv文件,c,csv,strtok,C,Csv,Strtok,我正在尝试使用C中的strtok读取csv文件,并将内容存储到struct Game的数组中。 我的代码如下所示: FILE *fp; int i = 0; if((fp=fopen("Games.csv","r"))==NULL) { printf("Can't open file.\n"); exit(1); } rewind(fp); char buff[1024]; fgets(buff,1024,fp); char*
FILE *fp;
int i = 0;
if((fp=fopen("Games.csv","r"))==NULL)
{
printf("Can't open file.\n");
exit(1);
}
rewind(fp);
char buff[1024];
fgets(buff,1024,fp);
char* delimiter = ",";
while(fgets(buff, 1024, (FILE*)fp)!=NULL && i<5){
Game[i].ProductID= strtok(buff, ",");
Game[i].ProductName = strtok(NULL, delimiter);
Game[i].Publisher = strtok(NULL, delimiter);
Game[i].Genre = strtok(NULL, delimiter);
Game[i].Taxable = atoi(strtok(NULL, delimiter));
Game[i].price = strtok(NULL, delimiter);
Game[i].Quantity = atoi(strtok(NULL, delimiter));
printf("%s\n", Game[i].ProductID);
i++;
}
i = 0;
for(i = 0; i<5; i++){
printf("%s", Game[i].ProductID);
}
前五行(while循环中)是正确的。但是,最后五行(while循环之外)是错误的,它将打印整行内容
我对此很困惑。当数组被更改时,以及如何在while循环后仍然打印正确答案。首先,介绍一下strok()的工作原理。该函数将返回一个指向原始字符串中某个位置的指针,该字符串已被修改,使其看起来像只有一个标记(a) 例如,
“A,B,C”
的第一个strtok
会将其转换为“A\0B,C”
,并返回A
字符的地址。在这一点上使用它会给你一个“A”
类似地,第二次调用会将其转换为“A\0B\0C”
,并返回B
字符的地址
它向您提供指向原始字符串的指针这一事实在这里至关重要,因为原始字符串位于buff
中
而且,每次从文件中读取一行内容时,实际上都会覆盖buff
。因此,对于所有这五行,Game[i].ProductID
将只是buff
的第一个字符的地址。处理完第五行后,该行:
while (fgets(buff, 1024, fp) != NULL && i < 5)
记住,您应该在某个时候释放这些内存分配
在极不可能的情况下,您的环境没有strdup
(它是POSIX而不是ISO),请参阅
另外,作为旁白,大多数CSV实现都允许嵌入逗号,例如将它们括在引号中或转义它们(后者很少见,但我见过):
这两个字段都可能是三个字段,name
,diablo,pax
和awesome
使用strtok
简化处理将不允许出现这种复杂性,但是,假设您的字段不包含嵌入的逗号,这可能是可以的。如果您的输入更复杂,您最好使用第三方CSV库(当然有合适的许可证)
(a) 对于我们当中的语言律师,ISO C标准、
C117.24.5.8 strtok函数、/3和/4
(我的粗体)中包含了这一点:
3/序列中的第一个调用在s1
指向的字符串中搜索s2
指向的当前分隔符字符串中不包含的第一个字符。如果未找到此类字符,则s1
指向的字符串中没有标记,strtok
函数返回空指针。如果找到这样一个字符,它是第一个标记的开始
4/然后,strtok
函数从中搜索包含在当前分隔符字符串中的字符。如果未找到此类字符,则当前标记将扩展到由s1
指向的字符串的末尾,随后对标记的搜索将返回空指针。如果找到这样一个字符,它将被一个空字符覆盖,从而终止当前令牌。strok函数保存指向以下字符的指针,下一次搜索令牌将从该字符开始
首先,介绍
strtok()
的工作原理。该函数将返回一个指向原始字符串中某个位置的指针,该字符串已被修改,使其看起来像只有一个标记(a)
例如,“A,B,C”
的第一个strtok
会将其转换为“A\0B,C”
,并返回A
字符的地址。在这一点上使用它会给你一个“A”
类似地,第二次调用会将其转换为“A\0B\0C”
,并返回B
字符的地址
它向您提供指向原始字符串的指针这一事实在这里至关重要,因为原始字符串位于buff
中
而且,每次从文件中读取一行内容时,实际上都会覆盖buff
。因此,对于所有这五行,Game[i].ProductID
将只是buff
的第一个字符的地址。处理完第五行后,该行:
while (fgets(buff, 1024, fp) != NULL && i < 5)
记住,您应该在某个时候释放这些内存分配
在极不可能的情况下,您的环境没有strdup
(它是POSIX而不是ISO),请参阅
另外,作为旁白,大多数CSV实现都允许嵌入逗号,例如将它们括在引号中或转义它们(后者很少见,但我见过):
这两个字段都可能是三个字段,name
,diablo,pax
和awesome
使用strtok
简化处理将不允许出现这种复杂性,但是,假设您的字段不包含嵌入的逗号,这可能是可以的。如果您的输入更复杂,您最好使用第三方CSV库(当然有合适的许可证)
(a) 对于我们当中的语言律师,ISO C标准、
C117.24.5.8 strtok函数、/3和/4
(我的粗体)中包含了这一点:
3/序列中的第一个调用在s1
指向的字符串中搜索s2
指向的当前分隔符字符串中不包含的第一个字符。如果未找到此类字符,则s1
指向的字符串中没有标记,strtok
函数返回空指针。如果找到这样一个字符,它是第一个标记的开始
4/然后,strtok
函数从那里搜索包含的字符
name,"diablo, pax",awesome
name,diablo\, pax,awesome