鱼C论坛

 找回密码
 立即注册
查看: 4312|回复: 5

怎么将csv数据导入c或c++中的数组中,希望给实例

[复制链接]
发表于 2021-2-6 00:02:00 From FishC Mobile | 显示全部楼层 |阅读模式
10鱼币
怎么将csv数据导入c或c++中的数组中,希望给实例

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-2-6 06:44:05 From FishC Mobile | 显示全部楼层
网上使用 c调用csv源码几乎没有
一定要用c.的话,就得自己想办法了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-2-6 09:02:52 | 显示全部楼层
csv 文件是纯文本文件,用逗号,换行符分割的纯文本文件,逗号分割列,换行符号分割行,处理起来非常简单。
C 的话用链表处理比较方便,因为行、列未知,需动态分配内存。
typedef  struct tagCSVFile
{
     char *context;     //字符串指针存储内容
     int  flag;              //换行标志
     struct tagCSVFile * next;      
}CSV,*LPCSV; 

c++ 的话用  vector<vector<string> >  array;  存储非常方便。
简单流程如下
读入一段字符,查找逗号  ',' 和回车换行 \n\r,
如果找到逗号,则把逗号之前的字符串作为数组的一个元素。
继续查找下一个逗号和回车换行,找到回车换行则把回车换行符之前的字符串作为数组的一个元素,并对数组做换行处理。
处理完毕,继续读取下一段字符,重复之前的动作,直到文件结束。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-2-6 09:33:32 | 显示全部楼层
csv 文件不就是使用 "," 做列分割,使用 "\n" 做行分割的 txt 文件吗
所以,先写一个
char** split(const char* str, const char* sep)
来切分字符串,然后

const char * input = "";
char** lines = split(input, "\n")
for (char* line = *lines; line != NULL; line++) {
    char** colunms = split(line, ",")
}

FYI:
https://github.com/p-ranav/csv2
https://github.com/ben-strasser/fast-cpp-csv-parser
https://github.com/vincentlaucsb/csv-parser
https://github.com/rgamble/libcsv

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-2-7 09:50:26 | 显示全部楼层
先上代码测试, 然后再解释
/*
        used: UTF-8
*/
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>

int main(void)
{
        char ***data = NULL;                //储存所读取的数据---实际上可以翻译为:(*data)[][], 即储存字符串的二维数组
        FILE *fp;                                        //要读取的文件指针
        int i, j, k = 0;                        //计数器
        int temp;                                        //临时数据
        char gets_test = '\0';                //读取的字符
        int lines = 1;                                //被读取文件的行数

        //打开文件
        if ((fp = fopen("test.csv", "r")) == NULL)
        {
                return -1;
        }

        //读取文件的行数
        while (!feof(fp))
        {
                gets_test = fgetc(fp);
                if (gets_test == '\n')
                {
                        lines++;
                }
        }
        gets_test = '\0';                        //将字符清空, 以便后面的判断
        rewind(fp);                                        //回到文件开始位置

        int num[lines];                                //文件中每行数据的个数
        //初始化
        for (i = 0; i < lines; i++)
        {
                num[i] = 1;
        }

        //读取文件中每行数据的个数
        for (i = 0; i < lines; i++)
        {
                while (gets_test != '\n')
                {
                        gets_test = fgetc(fp);
                        if (gets_test == ',')
                        {
                                num[i]++;
                        }
                        if (gets_test == EOF)
                        {
                                goto exits;                        //如果读取到文件末, 则直接跳转到exits继续进行下一步
                        }
                }
                gets_test = '\0';                        //对读取到的字符进行重置, 避免因读到'\n'而导致无法读取下一行
        }
exits:
        rewind(fp);                                         //回到文件开始位置

        int num_max;                                        //文件中, 在所有行中, 每行数据个数最多的值
        int temp_num[lines];                        //每行数据个数的临时数据

        //将数据复制到临时数据中, 以便进行
        memcpy(temp_num, num, sizeof(int) * lines);

        //当文件行数超过一行时, 对数据个数进行排序, 得出最大值[此处使用降序]
        if (lines > 1)
        {
                for (i = 1; i <= lines; i++)
                {
                        for (j = 0; j < lines; j++)
                        {
                                if (temp_num[i - 1] < temp_num[i])
                                {
                                        temp = temp_num[i - 1];
                                        temp_num[i - 1] = temp_num[i];
                                        temp_num[i] = temp;
                                }
                        }
                }

                num_max = temp_num[0];
        }
        else
        {
                num_max = num[0];                                //当文件只有一行时, 最大值就是当前行的数据个数
        }

        //每行每个数据的具体大小, 这里直接设置每行数据个数的最大值
        //当然, 这里设置成指针再进行其他操作也行, 不过复杂度就相对较高了
        int test[lines][num_max];

        //对数组进行初始化
        for (i = 0; i < lines; i++)
        {
                for (j = 0; j < num_max; j++)
                {
                        test[i][j] = 0;
                }
        }

        //读取数据
        for (i = 0; i < lines; i++)
        {
                gets_test = ' ';
                for (j = 0; (gets_test != '\n' && gets_test != EOF);j++)
                {
                        gets_test = fgetc(fp);
                        if (gets_test == ',' || gets_test == '\n' || gets_test == EOF)
                        {
                                test[i][k] = j;
                                j = -1;                                                        //这里之所以为-1是因为for循环会多加一个1
                                if (k < (num[i] - 1))                        //这里防止数组越界
                                {
                                        k++;
                                }
                        }
                }
                k = 0;                                                                        //当i发生变化时, 需要对k进行重置, 否则将无法读取下一行与当前数据同样位置的数据z
        }
        rewind(fp);

        //对data进行动态申请内存, 以尽量不浪费内存
        data = (char ***)malloc(sizeof(char ***) * lines);
        for (i = 0; i < lines; i++)
        {
                data[i] = (char **)malloc(sizeof(char **) * num[i]);
                for (j = 0; j < num[i]; j++)
                {
                        data[i][j] = (char *)malloc(sizeof(char *) * (test[i][j]));
                }
        }

        //对申请的内存进行初始化, 以防乱码等情况
        for (i = 0; i < lines; i++)
        {
                for (j = 0; j < num[i]; j++)
                {
                        for (k = 0; k < test[i][j]; k++)
                        {
                                memset(data[i][j], 0, sizeof(char *) * (test[i][j]));
                        }
                }
        }

        //读取信息并储存到data中
        for (i = 0; i < lines; i++)
        {
                //将num[i]作为临时数据
                temp = num[i];
                //对读取到的数据个数进行判断后再读取
                for (j = 0; temp > 0; j++)
                {
                        //重置k以免因特殊字符而导致多读取或少读取的情况
                        k = 0;
                        for (k = 0; k < test[i][j]; k++)
                        {
                                gets_test = fgetc(fp);
                                if (gets_test != ',' && gets_test != '\n')
                                {
                                        data[i][j][k] = gets_test;
                                }
                                else
                                {
                                        //当读取到的数据为特殊字符时, 对k进行赋值
                                        //这里之所以是-1也是因为for循环的问题, 循环结束后会执行k++, 易导致读取的数据不完整
                                        k = -1;
                                }
                        }
                        //当前行当前个数的数据读取完之后, 进行赋值, 以便判断, 防止造成数组越界等情况
                        temp--;
                }
        }
        
        //打印读取到的数据并确认
        for (i = 0; i < lines; i++)
        {
                for (j = 0; j < num[i]; j++)
                {
                        printf("%s ", data[i][j]);
                }
                putchar(10);
        }

        fclose(fp);                //关闭文件
        free(data);                //释放data

        getch();
        return 0;
}
实例如下:
第一次调试:
1,2,3,4,5,6,7,8,9,10,11,12
q,w,e,r,t,y,u,i,o,p,a,[,]
"?????","it's too dificult!!!","make it isn't so easy!"
输出:
1 2 3 4 5 6 7 8 9 10 11 12
q w e r t y u i o p a [ ]
"?????" "it's too dificult!!!" "make it isn't so easy!"
原谅我等级不够没法上传图片备注:GCC 4.8.1编译通过, 汉字会出现乱码, 因为汉字是占两个字节的, 而本程序是一个字节一个字节读的

吐槽一下:这个东西是真的难写, 倒不是说逻辑上有多难, 那个三级指针就调试了挺久的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-2-8 14:13:23 | 显示全部楼层
fopen 然后 fscanf 不就行了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-14 19:04

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表