在C语言中将.csv文件解析为二维数组

3

我有一个类似于以下格式的 .csv 文件:

SKU,Plant,Qty
40000,ca56,1245
40000,ca81,12553.3
40000,ca82,125.3
45000,ca62,0
45000,ca71,3
45000,ca78,54.9

注意:这只是我的示例,但实际上有大约500,000行和3列。
我试图将这些条目转换为2D数组,以便我可以操纵数据。您会注意到,在我的示例中,我只设置了一个小的10x10矩阵A,以尝试使此示例正常工作,然后再转向真正的数据。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const char *getfield(char *line, int num);

int main() {
    FILE *stream = fopen("input/input.csv", "r");
    char line[1000000];
    int A[10][10];
    int i, j = 0;

    //Zero matrix
    for (i = 0; i < 10; i++) {
        for (j = 0; j < 10; j++) {
            A[i][j] = 0;
        }
    }

    for (i = 0; fgets(line, 1000000, stream); i++) {
        while (j < 10) {
            char *tmp = strdup(line);
            A[i][j] = getfield(tmp, j);
            free(tmp);
            j++;
        }
    }
    //print matrix
    for (i = 0; i < 10; i++) {
        for (j = 0; j < 10; j++) {
            printf("%s\t", A[i][j]);
        }
        printf("\n");
    }
}

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 0;
}

它仅打印“null”错误,我认为这与此行的指针有关:A [i] [j] = getfield(tmp,j)。但我真的不确定如何修正它。
这项工作几乎完全基于这个问题: 在C中读取.CSV文件。非常感谢任何帮助来适应它,因为距上次接触C或外部文件已经过去了几年。

1
getfield() 不会复制任何内容,它只是将 tmp 的一部分切割并返回。然后你将 tmp 的那部分赋值给矩阵中的一个位置,然后释放 tmp。(正如 @BLUEPIXY 指出的,tmp 甚至没有定义为保存字符串)如果你要在 A 中存储指针,你必须保持它们分配直到你完成使用它们为止。(我还没有读过这行代码之后的内容,所以可能还有更多要来...) - ebyrob
if (!--num) --> if (!num--) - BLUEPIXY
  1. 你需要重置 j。像这样 j = 0; while(j<10){ 或者使用 for
- BLUEPIXY
1
@ebyrob 基本上这些问题大多数都是离题的。 - BLUEPIXY
会注意的,谢谢。 - Matthew R
显示剩余8条评论
2个回答

1
看起来评论者已经帮助您找到了代码中的一些错误。然而,这些问题相当深入。其中最大的问题之一是您正在使用字符串。字符串当然是字符数组;这意味着已经有一个维度在使用中。
最好只使用像这样的结构体:
struct csvTable
{
    char sku[10];
    char plant[10];
    char qty[10];
};

那样可以让你设置正确的数据类型,比如SKU可能是一个整数,但我不知道具体情况。以下是实现示例,抱歉有些混乱,它是根据我已经在处理的内容即兴调整的。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Based on your estimate
// You could make this adaptive or dynamic

#define rowNum 500000

struct csvTable
{
    char sku[10];
    char plant[10];
    char qty[10];
};

// Declare table
struct csvTable table[rowNum];

int main()
{
    // Load file
    FILE* fp = fopen("demo.csv", "r");

    if (fp == NULL)
    {
        printf("Couldn't open file\n");
        return 0;
    }

    for (int counter = 0; counter < rowNum; counter++)
    {
        char entry[100];
        fgets(entry, 100, fp);

        char *sku = strtok(entry, ",");
        char *plant = strtok(NULL, ",");
        char *qty = strtok(NULL, ",");

        if (sku != NULL && plant != NULL && qty != NULL)
        {
            strcpy(table[counter].sku, sku);
            strcpy(table[counter].plant, plant);
            strcpy(table[counter].qty, qty);
        }
        else
        {
            strcpy(table[counter].sku, "\0");
            strcpy(table[counter].plant, "\0");
            strcpy(table[counter].qty, "\0");
        }
    }

    // Prove that the process worked
    for (int printCounter = 0; printCounter < rowNum; printCounter++)
    {
        printf("Row %d: column 1 = %s, column 2 = %s, column 3 = %s\n", 
            printCounter + 1, table[printCounter].sku, 
            table[printCounter].plant, table[printCounter].qty);
    }

    // Wait for keypress to exit
    getchar();

}

1
你的代码存在多个问题:
  • 在第二个循环中,你没有在读取10行后停止读取文件,因此你会尝试存储超出 A 数组末尾的元素。
  • 你没有在 while (j < 10) 循环开始时将 j 重置为 0。在初始化循环结束时,j 恰好具有值 10,因此实际上没有将任何内容存储到矩阵中。
  • 矩阵 A 应该是一个二维 char * 数组,而不是 int,或者可能是一个结构体数组。

这里有一个更简单的版本,使用了分配的结构体数组:

#include <stdio.h>
#include <stdlib.h>

typedef struct item_t {
    char SKU[20];
    char Plant[20];
    char Qty[20];
};

int main(void) {
    FILE *stream = fopen("input/input.csv", "r");
    char line[200];
    int size = 0, len = 0, i, c;
    item_t *A = NULL;

    if (stream) {
        while (fgets(line, sizeof(line), stream)) {
            if (len == size) {
                size = size ? size * 2 : 1000;
                A = realloc(A, sizeof(*A) * size);
                if (A == NULL) {
                    fprintf(stderr, "out of memory for %d items\n", size);
                    return 1;
                }
            }
            if (sscanf(line, "%19[^,\n],%19[^,\n],%19[^,\n]%c",
                       A[len].SKU, A[len].Plant, A[len].Qty, &c) != 4
            ||  c != '\n') {
                fprintf(stderr, "invalid format: %s\n, line);
            } else {
                len++;
            }
        }
        fclose(stream);

        //print matrix
        for (i = 0; i < len; i++) {
            printf("%s,%s,%s\n", A[i].SKU, A[i].Plant, A[i].Qty);
        }
        free(A);
    }
    return 0;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接