简体   繁体   English

读取csv文件到c结尾

[英]read csv file to its end in c

So I have this code that reads a bunch of lines from a csv document. 因此,我有这段代码可以从csv文档中读取很多行。 I know that initially the document has 16 rows, and that's why I designated int noRows = 16; 我知道文档最初有16行,这就是为什么我指定int noRows = 16; in my main funtion. 在我的主要功能上。

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] = '\0'; // 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);

} }

My question is how do I read the file to its end without first knowing how many rows it has? 我的问题是,如何在不知道文件有多少行的情况下读取文件的末尾? I'm thinking of having a specific cell in the file just to save noRows between startup and shutdown of console. 我正在考虑在文件中具有特定的单元格,只是为了保存控制台启动和关闭之间的noRows

I tried using char buffer[1000]; while(fgets(buffer, 1000, fp)) {} 我尝试使用char buffer[1000]; while(fgets(buffer, 1000, fp)) {} char buffer[1000]; while(fgets(buffer, 1000, fp)) {} but then it reads the first 8 rows(not sure if it's always exactly 8) as 0,0,0,0,0,0,0,0,0,0. char buffer[1000]; while(fgets(buffer, 1000, fp)) {} ,然后它读取前8行(不确定是否总是8)作为0,0,0,0,0,0,0,0,0,0 。

The answer to your question if just test the return value of fgets 您的问题的答案是否只是测试fgets的返回值

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
    ...

But as you were told in comments, there are many other problems in your code: 但是正如您在注释中告诉您的那样,您的代码中还有许多其他问题:

  • you initialize your indexes to 1 while C array indexes start at 0. So I assume that x=1; 您将索引初始化为1,而C数组索引从0开始x=1; should be x=0; 应该是x=0; . For the same reason, countTok = 1; 由于相同的原因, countTok = 1; is not wrong, but countTok = 0; 没错,但是countTok = 0; would be more idiomatic C 会更惯用C
  • you use fprintf(stderr, ... to notice an error when opening the file. While not wrong, it gives no indication on the cause of the error. perror would do... 您可以使用fprintf(stderr, ...在打开文件时注意到错误。虽然没有错,但它并未指出错误原因perror可以...
  • you erase last character of oneproduct without controling it is a newline. 你删除的最后一个字符oneproduct没有controling它是一个换行符。 The assumption will be wrong 这个假设是错误的

    • if one line contains at least 256 characters 如果一行至少包含256个字符
    • if last line does not end with a newline 如果最后一行不以换行符结尾

    The idiomatic way is to use strcspn : 惯用的方法是使用strcspn

     oneproduct[strcspn(oneproduct, "\\n")] = '\\0'; // erase an optional end of line 
  • you duplicate oneproduct to oneline . 您将oneproduct复制到oneline Here again, nothing is wrong, but it is useless because you never use the original line 同样,这没什么错,但是这没用,因为您永远不会使用原始行
  • the long list of else if could be replaced with a switch, but this one is mainly a matter of style 一长串的else if是否可以用开关代替,但这主要是样式问题
  • you free token at the end of loop. 您可以在循环结束时释放token As it is NULL it is a no-op, but it is was not allocated it should not be freed. 因为它为NULL,所以它是一个空操作,但未分配它,因此不应释放它。

If you're using fgets , you can test if the result of the call is equal to NULL or not. 如果使用的是fgets ,则可以测试调用的结果是否等于NULL fgets signals NULL on error or EOF (end-of-file). fgets在错误或EOF (文件结束)时发出NULL信号。

char *fgets(char *line, int maxline, FILE *fp); .

IE: IE:

while (fgets(buffer, MAXLINE, fp) != NULL) {
    // Process line here.
}

You can also process the entire file character by character and test if (c == EOF) . 您还可以逐个字符地处理整个文件,并测试(c == EOF) There are a couple of ways to do it. 有两种方法可以做到这一点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM