在c中读取csv文件到最后
read csv file to its end in c
所以我有这段代码可以从 csv 文档中读取一堆行。我知道最初文档有 16 行,这就是为什么我在我的主要功能中指定 int noRows = 16;
。
void readBeer(int noRows) {
char *oneline, *token;
char oneproduct[256];
char delim[] = ",";
int x = 1;
FILE *fp; //open file
if ((fp = fopen("varor.csv", "r")) == NULL) //can the file be opened?
{
fprintf(stderr, "File varor.csv couldn't be opened\n"); //"couldn't open file"
exit(-1);
}
while(noRows != 0)
{
int countTok = 1;
fgets(oneproduct, 256, fp); //get the first row
oneproduct[strlen(oneproduct) - 1] = '[=10=]'; // remove end-of-line character
oneline = strdup(oneproduct); //duplicate oneproduct into oneline because strtok modifies the given string
token = strtok(oneline, delim); //split oneline into tokens, tokens are separated by ","
while (token != NULL)
{
if(countTok == 1) beer[x].productNumber = atoi(token);
else if(countTok == 2) strcpy(beer[x].name, token);
else if(countTok == 3) beer[x].price = atof(token);
else if(countTok == 4) beer[x].volume = atof(token);
else if(countTok == 5) strcpy(beer[x].type, token);
else if(countTok == 6) strcpy(beer[x].style, token);
else if(countTok == 7) strcpy(beer[x].packaging, token);
else if(countTok == 8) strcpy(beer[x].country, token);
else if(countTok == 9) strcpy(beer[x].manufacturer, token);
else if(countTok == 10) beer[x].alcohol = atof(token);
else printf("kossan hoppade!"); //should never be seen in console
token = strtok(NULL, delim);
countTok++;
}
x++;
noRows--;
free(oneline); free(token);
}
fclose(fp);
}
我的问题是如何在不知道文件有多少行的情况下将文件读到底?我正在考虑在文件中有一个特定的单元格,只是为了在控制台启动和关闭之间保存 noRows
。
我尝试使用 char buffer[1000]; while(fgets(buffer, 1000, fp)) {}
但随后它读取前 8 行(不确定它是否始终正好是 8)作为 0,0,0,0,0,0,0,0,0,0 .
如果您正在使用 fgets
,您可以测试调用的结果是否等于 NULL
。fgets
在错误或错误时发出信号 NULL
EOF
(文件结束)。
char *fgets(char *line, int maxline, FILE *fp);
.
I.E:
while (fgets(buffer, MAXLINE, fp) != NULL) {
// Process line here.
}
您还可以逐个字符地处理整个文件并测试是否(c == EOF)
。有几种方法可以做到这一点。
如果只需测试 fgets
的 return 值,您问题的答案
for (;;) // idiomatic C style for an infinite loop
{
int countTok = 1;
if (NULL == fgets(oneproduct, 256, fp)) break; //get one row and exit loop on EOF
...
但是正如评论中所说,您的代码中还有许多其他问题:
- 您将索引初始化为 1,而 C 数组索引从 0 开始。所以我假设
x=1;
应该是 x=0;
。出于同样的原因,countTok = 1;
没有错,但 countTok = 0;
会更地道 C
- 您使用
fprintf(stderr, ...
打开文件时发现错误。虽然没有错,但它没有给出错误原因的指示。 perror
会做...
你删除了 oneproduct
的最后一个字符而不控制它是一个换行符。假设会错
- 如果一行至少包含 256 个字符
- 如果最后一行不以换行结束
惯用的方法是使用 strcspn
:
oneproduct[strcspn(oneproduct, "\n")] = '[=11=]'; // erase an optional end of line
- 您将
oneproduct
复制到 oneline
。又来了,没有错,但是没用,因为你从来没有用过原来的行
- 一长串
else if
可以换成switch,不过这个主要是风格问题
- 你在循环结束时释放
token
。因为它是 NULL,所以它是一个空操作,但它没有被分配,所以不应该被释放。
所以我有这段代码可以从 csv 文档中读取一堆行。我知道最初文档有 16 行,这就是为什么我在我的主要功能中指定 int noRows = 16;
。
void readBeer(int noRows) {
char *oneline, *token;
char oneproduct[256];
char delim[] = ",";
int x = 1;
FILE *fp; //open file
if ((fp = fopen("varor.csv", "r")) == NULL) //can the file be opened?
{
fprintf(stderr, "File varor.csv couldn't be opened\n"); //"couldn't open file"
exit(-1);
}
while(noRows != 0)
{
int countTok = 1;
fgets(oneproduct, 256, fp); //get the first row
oneproduct[strlen(oneproduct) - 1] = '[=10=]'; // remove end-of-line character
oneline = strdup(oneproduct); //duplicate oneproduct into oneline because strtok modifies the given string
token = strtok(oneline, delim); //split oneline into tokens, tokens are separated by ","
while (token != NULL)
{
if(countTok == 1) beer[x].productNumber = atoi(token);
else if(countTok == 2) strcpy(beer[x].name, token);
else if(countTok == 3) beer[x].price = atof(token);
else if(countTok == 4) beer[x].volume = atof(token);
else if(countTok == 5) strcpy(beer[x].type, token);
else if(countTok == 6) strcpy(beer[x].style, token);
else if(countTok == 7) strcpy(beer[x].packaging, token);
else if(countTok == 8) strcpy(beer[x].country, token);
else if(countTok == 9) strcpy(beer[x].manufacturer, token);
else if(countTok == 10) beer[x].alcohol = atof(token);
else printf("kossan hoppade!"); //should never be seen in console
token = strtok(NULL, delim);
countTok++;
}
x++;
noRows--;
free(oneline); free(token);
}
fclose(fp);
}
我的问题是如何在不知道文件有多少行的情况下将文件读到底?我正在考虑在文件中有一个特定的单元格,只是为了在控制台启动和关闭之间保存 noRows
。
我尝试使用 char buffer[1000]; while(fgets(buffer, 1000, fp)) {}
但随后它读取前 8 行(不确定它是否始终正好是 8)作为 0,0,0,0,0,0,0,0,0,0 .
如果您正在使用 fgets
,您可以测试调用的结果是否等于 NULL
。fgets
在错误或错误时发出信号 NULL
EOF
(文件结束)。
char *fgets(char *line, int maxline, FILE *fp);
.
I.E:
while (fgets(buffer, MAXLINE, fp) != NULL) {
// Process line here.
}
您还可以逐个字符地处理整个文件并测试是否(c == EOF)
。有几种方法可以做到这一点。
如果只需测试 fgets
的 return 值,您问题的答案for (;;) // idiomatic C style for an infinite loop
{
int countTok = 1;
if (NULL == fgets(oneproduct, 256, fp)) break; //get one row and exit loop on EOF
...
但是正如评论中所说,您的代码中还有许多其他问题:
- 您将索引初始化为 1,而 C 数组索引从 0 开始。所以我假设
x=1;
应该是x=0;
。出于同样的原因,countTok = 1;
没有错,但countTok = 0;
会更地道 C - 您使用
fprintf(stderr, ...
打开文件时发现错误。虽然没有错,但它没有给出错误原因的指示。perror
会做... 你删除了
oneproduct
的最后一个字符而不控制它是一个换行符。假设会错- 如果一行至少包含 256 个字符
- 如果最后一行不以换行结束
惯用的方法是使用
strcspn
:oneproduct[strcspn(oneproduct, "\n")] = '[=11=]'; // erase an optional end of line
- 您将
oneproduct
复制到oneline
。又来了,没有错,但是没用,因为你从来没有用过原来的行 - 一长串
else if
可以换成switch,不过这个主要是风格问题 - 你在循环结束时释放
token
。因为它是 NULL,所以它是一个空操作,但它没有被分配,所以不应该被释放。