【问题标题】:reading CSV in C when the table is broken表格损坏时在 C 中读取 CSV
【发布时间】:2012-10-30 06:13:07
【问题描述】:

这是我读取 CSV 文件的 C 代码:

#include <stdio.h>
struct record
{long a,b,c;    };

int main(void)
{
    const char filename[] = "b.csv";
    FILE *file = fopen(filename, "r");

    if ( file != NULL )
    {
        char line [ 80 ];
        struct record record [ 50 ];
        size_t count, i = 0;

        while ( i < sizeof record / sizeof *record )
        {
            if ( fgets(line, sizeof line, file) == NULL )
            {
                break;
            }

            if ( sscanf(line, "%ld,%ld,%ld", &record[i].a,&record[i].b,&record[i].c) == 3 )
            {
                ++i;
            }
        }
        fclose(file);

        for ( count = i, i = 0; i < count; ++i )
        {
            printf("record[%lu]: a = %ld b = %ld c = %ld\n",
                (long unsigned)i, record[i].a, record[i].b,record[i].c);
            }
    }
    else
    {
        perror(filename);
    }
    return 0;
}

/* 文件.csv

301,36,15
302,88,75

/ / 我的输出

record[0]: a = 301 b = 36 c = 15
record[1]: a = 302 b = 88 c = 75

*/

上面的代码有两个问题..

第一个问题是: /* 文件.csv

 301,,15
 302,88,
 ,,,34

输出应该是

record[0]: a = 301 b = 0 c = 15
record[1]: a = 302 b = 88 c = 0
record[2]: a = 0 b = 0 c = 34

第二个问题是它应该读取文件直到“eof”。这里我取 50 作为静态行号值。我应该做些什么改变?

看到我已经以这种方式更改了代码...

  const char* getfield(char* line, int num) {
        const char* tok;
        for (tok = strtok(line, ",");
                tok && *tok;
                tok = strtok(NULL, ",\n"))
        {
            if (!--num)
                return tok;
        }
        return NULL;
    }

    int main()
    {
        FILE* stream = fopen("b.csv", "r");
        char line[1024];
        char *pstr;int num;
         const char* value;

        while (fgets(line, 1024, stream))
        {
            char* tmp = strdup(line);
        //printf("Field 3 would be %s\n", getfield(tmp, 3));    
        value=getfield(tmp, 3);
        num =strtol(value,&pstr,10);
        printf("Field 3 would be %d\n", num);
        // NOTE strtok clobbers tmp
            free(tmp);
        }
    }

【问题讨论】:

  • 考虑 sscanf 的返回值表示实际完成了多少次分配并相应地放入数据成员中
  • 您也可以读取一行并将strtok应用于逗号,然后将值放入数据中

标签: c csv file-handling


【解决方案1】:

而不是

sscanf(line, "%ld,%ld,%ld", &record[i].a,&record[i].b,&record[i].c)

行,您可以使用strtok_r() 函数(documentation)将行拆分为逗号分隔的子字符串。然后在每个子字符串上,要么执行strtol() 调用(documentation)以获取其整数值,要么将相应的变量设置为0,如果它是一个空字符串。

您可以使用检查空字符串

if (str[0] == 0) {
    // empty
}

要读取直到EOF,只需检查fgets() 返回NULL 并检查if (feof(file)) - 如果到达文件末尾,fgets() 设置FILE * 流的 EOF 指示符,并且返回NULL

【讨论】:

  • strtok 在 NULL 值检查时给出了段错误.. 你能写出 NULL 值处理的完整方法吗..
  • @user95711 不,抱歉。你必须自己做出一些努力。
  • 我已经尝试过了,但是如果找到“123, ,110”,它会将 110 视为第二个数据!第三个仍然为空。如果我在空点使用“strtol”,它会给出段错误。否则它打印 NULL
  • printf("字段 3 将是 %s\n", getfield(tmp, 3));如果我“取消评论”这一行并在三以下“评论”它不会给出段错误..这里的另一个问题是如果我写第一个和第三个数据是考虑第三个作为第二个。第三个仍然是NULL,导致“segfault”
  • @user95711 你误用了“strtok”。您应该使用"," 作为分隔符,而不是",\n"
猜你喜欢
  • 2019-09-26
  • 1970-01-01
  • 2020-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-22
  • 1970-01-01
相关资源
最近更新 更多