鱼C论坛

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

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

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

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2021-2-6 06:44:05 From FishC Mobile | 显示全部楼层
网上使用 c调用csv源码几乎没有
一定要用c.的话,就得自己想办法了
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2021-2-6 09:02:52 | 显示全部楼层
csv 文件是纯文本文件,用逗号,换行符分割的纯文本文件,逗号分割列,换行符号分割行,处理起来非常简单。
C 的话用链表处理比较方便,因为行、列未知,需动态分配内存。

  1. typedef  struct tagCSVFile
  2. {
  3.      char *context;     //字符串指针存储内容
  4.      int  flag;              //换行标志
  5.      struct tagCSVFile * next;      
  6. }CSV,*LPCSV;
复制代码


c++ 的话用  vector<vector<string> >  array;  存储非常方便。
简单流程如下
读入一段字符,查找逗号  ',' 和回车换行 \n\r,
如果找到逗号,则把逗号之前的字符串作为数组的一个元素。
继续查找下一个逗号和回车换行,找到回车换行则把回车换行符之前的字符串作为数组的一个元素,并对数组做换行处理。
处理完毕,继续读取下一段字符,重复之前的动作,直到文件结束。
小甲鱼最新课程 -> https://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

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2021-2-7 09:50:26 | 显示全部楼层
先上代码测试, 然后再解释

  1. /*
  2.         used: UTF-8
  3. */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <conio.h>
  7. #include <string.h>

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

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

  21.         //读取文件的行数
  22.         while (!feof(fp))
  23.         {
  24.                 gets_test = fgetc(fp);
  25.                 if (gets_test == '\n')
  26.                 {
  27.                         lines++;
  28.                 }
  29.         }
  30.         gets_test = '\0';                        //将字符清空, 以便后面的判断
  31.         rewind(fp);                                        //回到文件开始位置

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

  38.         //读取文件中每行数据的个数
  39.         for (i = 0; i < lines; i++)
  40.         {
  41.                 while (gets_test != '\n')
  42.                 {
  43.                         gets_test = fgetc(fp);
  44.                         if (gets_test == ',')
  45.                         {
  46.                                 num[i]++;
  47.                         }
  48.                         if (gets_test == EOF)
  49.                         {
  50.                                 goto exits;                        //如果读取到文件末, 则直接跳转到exits继续进行下一步
  51.                         }
  52.                 }
  53.                 gets_test = '\0';                        //对读取到的字符进行重置, 避免因读到'\n'而导致无法读取下一行
  54.         }
  55. exits:
  56.         rewind(fp);                                         //回到文件开始位置

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

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

  61.         //当文件行数超过一行时, 对数据个数进行排序, 得出最大值[此处使用降序]
  62.         if (lines > 1)
  63.         {
  64.                 for (i = 1; i <= lines; i++)
  65.                 {
  66.                         for (j = 0; j < lines; j++)
  67.                         {
  68.                                 if (temp_num[i - 1] < temp_num[i])
  69.                                 {
  70.                                         temp = temp_num[i - 1];
  71.                                         temp_num[i - 1] = temp_num[i];
  72.                                         temp_num[i] = temp;
  73.                                 }
  74.                         }
  75.                 }

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

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

  85.         //对数组进行初始化
  86.         for (i = 0; i < lines; i++)
  87.         {
  88.                 for (j = 0; j < num_max; j++)
  89.                 {
  90.                         test[i][j] = 0;
  91.                 }
  92.         }

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

  113.         //对data进行动态申请内存, 以尽量不浪费内存
  114.         data = (char ***)malloc(sizeof(char ***) * lines);
  115.         for (i = 0; i < lines; i++)
  116.         {
  117.                 data[i] = (char **)malloc(sizeof(char **) * num[i]);
  118.                 for (j = 0; j < num[i]; j++)
  119.                 {
  120.                         data[i][j] = (char *)malloc(sizeof(char *) * (test[i][j]));
  121.                 }
  122.         }

  123.         //对申请的内存进行初始化, 以防乱码等情况
  124.         for (i = 0; i < lines; i++)
  125.         {
  126.                 for (j = 0; j < num[i]; j++)
  127.                 {
  128.                         for (k = 0; k < test[i][j]; k++)
  129.                         {
  130.                                 memset(data[i][j], 0, sizeof(char *) * (test[i][j]));
  131.                         }
  132.                 }
  133.         }

  134.         //读取信息并储存到data中
  135.         for (i = 0; i < lines; i++)
  136.         {
  137.                 //将num[i]作为临时数据
  138.                 temp = num[i];
  139.                 //对读取到的数据个数进行判断后再读取
  140.                 for (j = 0; temp > 0; j++)
  141.                 {
  142.                         //重置k以免因特殊字符而导致多读取或少读取的情况
  143.                         k = 0;
  144.                         for (k = 0; k < test[i][j]; k++)
  145.                         {
  146.                                 gets_test = fgetc(fp);
  147.                                 if (gets_test != ',' && gets_test != '\n')
  148.                                 {
  149.                                         data[i][j][k] = gets_test;
  150.                                 }
  151.                                 else
  152.                                 {
  153.                                         //当读取到的数据为特殊字符时, 对k进行赋值
  154.                                         //这里之所以是-1也是因为for循环的问题, 循环结束后会执行k++, 易导致读取的数据不完整
  155.                                         k = -1;
  156.                                 }
  157.                         }
  158.                         //当前行当前个数的数据读取完之后, 进行赋值, 以便判断, 防止造成数组越界等情况
  159.                         temp--;
  160.                 }
  161.         }
  162.         
  163.         //打印读取到的数据并确认
  164.         for (i = 0; i < lines; i++)
  165.         {
  166.                 for (j = 0; j < num[i]; j++)
  167.                 {
  168.                         printf("%s ", data[i][j]);
  169.                 }
  170.                 putchar(10);
  171.         }

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

  174.         getch();
  175.         return 0;
  176. }
复制代码

实例如下:
第一次调试:
  1. 1,2,3,4,5,6,7,8,9,10,11,12
  2. q,w,e,r,t,y,u,i,o,p,a,[,]
  3. "?????","it's too dificult!!!","make it isn't so easy!"
复制代码

输出:
  1. 1 2 3 4 5 6 7 8 9 10 11 12
  2. q w e r t y u i o p a [ ]
  3. "?????" "it's too dificult!!!" "make it isn't so easy!"
复制代码

原谅我等级不够没法上传图片备注:GCC 4.8.1编译通过, 汉字会出现乱码, 因为汉字是占两个字节的, 而本程序是一个字节一个字节读的

吐槽一下:这个东西是真的难写, 倒不是说逻辑上有多难, 那个三级指针就调试了挺久的
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2021-2-8 14:13:23 | 显示全部楼层
fopen 然后 fscanf 不就行了
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-5-1 22:27

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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