【问题标题】:How to read in txt file in CSV format and save into array in C如何以CSV格式读取txt文件并保存到C中的数组中
【发布时间】:2014-03-11 14:48:42
【问题描述】:

我是 C 新手,我需要读取一个 .txt 文件,其中每行有 3 个字段,用逗号分隔,我需要将其保存到一个数组中。我想知道如何做到这一点? 这是一个示例文件:

0, "test", 100
1, "hi", 2
2, "goodbye", 0

所以我想知道如何逐行读取文件并将每个元素存储到数组中。我从定义一个结构开始:

typedef struct data {
  int col1;
  char *col2;
  int col3;
} data_t;

谁能帮我开始打开文件?

【问题讨论】:

  • 您可以只使用libcsv 库。

标签: c arrays csv


【解决方案1】:

SQLite shell 有一个读取 CSV 的 .import 命令。值得研究。你可以找到它here;搜索 CSVReader 以查看其编码方式。

【讨论】:

    【解决方案2】:

    对于文件打开,有一个名为fopen 的标准库(包括stdio.h)函数。它有以下声明:

    FILE *fopen(const char *filename, const char *mode);
    

    如您所见,它希望您为文件名和模式(读/写/读+写)提供指向 const char 的指针。它将返回一个指向 FILE 的指针,因此在您打算使用它的函数中,您必须像这样声明一个:

    FILE *my_file;
    

    将其初始化为 NULL 也是一个好主意,这样您可以在使用 fopen 时检查错误。

    在你的主要功能中(纯粹为了阅读):

    FILE *my_file = NULL;
    my_file = fopen("filename.txt", "r");
    

    并检查返回的指针:

    if (my_file == NULL)
        //error message etc.
    

    【讨论】:

    • 这是我当时使用的语法,对吗? int main() { 文件 *my_file;文件 *fopen("数据", "r"); }
    • 好的,我现在明白了。那么这会打开整个文件还是只打开第一行?现在我要做的是读取格式为:int,string,int 的第一行,而我要做的是将每个字段存储为数组中的一个元素。根据我在网上找到的内容,我需要使用 strtok 函数。对吗?
    • @user2516663 它给你一个指向文件的指针。要获取单独的行,您可以使用 getline() 函数之类的东西。 strtok 是一种实现方式。您只需提供字符串和分隔符(在您的情况下为逗号)。
    • 嗯,我仍然对此感到困惑。所以 my_file 是指向我的 txt 文件的指针,现在我需要一个新变量来等于第一行吗?
    • @user2516663 查看this 链接。第一个答案让您了解如何进行逐行阅读以及涉及哪些变量。
    【解决方案3】:

    简单示例(检查省略)

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define NUMOFDATA 10
    
    typedef struct data {
        int col1;
        char *col2;
        int col3;
    } data_t;
    
    int main(){
        data_t data_array[NUMOFDATA];
        int data_count = 0;
        char line[128];
        FILE *fp;
        fp=fopen("data.txt", "r");
        while(fgets(line, sizeof(line), fp)){
            int col1, col3;
            char col2[64];
            if(sscanf(line, "%d, %63[^,], %d", &col1, col2, &col3)==3){
                char *cl2p = col2;
                data_array[data_count].col1 = col1;
                data_array[data_count].col3 = col3;
                if(col2[0] == '"'){
                    char *p = strchr(&col2[1], '"');
                    if(p)
                        *p = '\0';
                    cl2p = &col2[1];
                }
                data_array[data_count].col2 = strdup(cl2p);
    //printf("%d, \"%s\", %d\n",data_array[data_count].col1,data_array[data_count].col2,data_array[data_count].col3);
                if(++data_count == NUMOFDATA)break;
            }
        }
        fclose(fp);
        return 0;
    }
    

    【讨论】:

    • 我建议你在scanf字符串字段中使用m修饰符(即%m[^,],以便scanf为字符串分配内存。这使得整个事情更加健壮(否则你有一个缓冲区溢出)。另外,不要直接在文件上使用 fscanf 读取中间缓冲区。所以size_t data_count; for(data_count=0; i&lt;10; i++) { char **col2 = &amp;(data_array[i].col2); if( !fscanf(fp, "%d, %[^,], %d", &amp;(data_array[i].col1), col2, &amp;(data_array[i].col3) ) break; size_t c2l = strlen(*col2)-1; if( (*col2)[0]=='"' &amp;&amp; (*col2)[c2l]=='"' ) memmove(*col2, *col2+1, c2l-1); }
    • @datenwolf 这是一个不提供此类检查的计划,但根据您的建议添加。但它没有添加m 选项,因为没有共同点。我留下提问者的选择。
    • 那么正确的测试应该是0 &lt; fscanf(…),因为E… 代码是否定的。
    • @datenwolf 最好简单测试一下元素个数。
    • 如果除第一列之外的所有列都是可选的?
    猜你喜欢
    • 2012-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-11
    • 2022-01-05
    相关资源
    最近更新 更多