【问题标题】:read csv file to its end in c在c中读取csv文件到它的结尾
【发布时间】:2018-01-12 11:35:08
【问题描述】:

所以我有这段代码可以从 csv 文档中读取一堆行。我知道最初文档有 16 行,这就是我在 main 函数中指定 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] = '\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);

}

我的问题是如何在不知道文件有多少行的情况下将文件读到末尾?我正在考虑在文件中添加一个特定单元格,以便在控制台启动和关闭之间保存noRows

我尝试使用 char buffer[1000]; while(fgets(buffer, 1000, fp)) {},但它读取前 8 行(不确定它是否总是正好 8)为 0,0,0,0,0,0,0,0,0,0。

【问题讨论】:

  • 您是否尝试检查您是否达到 EOF?顺便说一句:您确定最后一行包含值的末尾包含 \n 吗?
  • 请使用 switch(),其他很多 if-s 看起来很糟糕。
  • 当我使用缓冲区时,它在最后一行之后停止,所以它注册了 EOF,是的。最后一行的 \n 有什么关系?
  • @Gnqz 我通常希望它在我让它看起来不错之前工作,但我会编辑它。
  • 关于您的实际问题:您重新设计的尝试很有希望。尝试getline() 而不是fgets()。如果失败则返回-1

标签: c csv eof


【解决方案1】:

如果只测试 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
    ...

但正如您在 cmets 中所说的,您的代码中还有许多其他问题:

  • 您将索引初始化为 1,而 C 数组索引从 0 开始。所以我假设 x=1; 应该是 x=0;。出于同样的原因,countTok = 1; 没有错,但countTok = 0; 会更惯用 C
  • 您使用fprintf(stderr, ... 在打开文件时发现错误。虽然没有错,但它没有说明错误的原因。 perror 可以...
  • 你删除oneproduct 的最后一个字符而不控制它是一个换行符。假设是错误的

    • 如果一行包含至少 256 个字符
    • 如果最后一行不以换行符结尾

    惯用的方式是使用strcspn:

    oneproduct[strcspn(oneproduct, "\n")] = '\0';  // erase an optional end of line
    
  • 您将oneproduct 复制到oneline。再说一遍,没有错,但没用,因为您从不使用原始行
  • else if 的长列表可以用开关代替,但这主要是风格问题
  • 在循环结束时释放token。因为它是 NULL,所以它是一个空操作,但它没有被分配,它不应该被释放。

【讨论】:

    【解决方案2】:

    如果您使用fgets,您可以测试调用结果是否等于NULLfgets 表示错误时NULLEOF(文件结束) .

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

    IE:

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

    您还可以逐字符处理整个文件并测试是否为(c == EOF)。有几种方法可以做到这一点。

    【讨论】:

      猜你喜欢
      • 2018-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-23
      相关资源
      最近更新 更多