Loading

Libcsv库解析csv格式文件

一、问题引入#

数据通信和数据存储的格式是多种多样的,不同的人会选择不同的数据格式,这就涉及数据格式的转换。

csv格式的文件在数据通信和存储使用较多,有必要记录一下csv格式文件的读写。

二、解决过程#

编写程序的一个重要原则:切记不要重复造轮子。 查询到处理csv格式文件的开源库:libcsv

关于libcsv的详细说明,请自行参考开源地址中 csv.pdf

解析csv格式文件

💡 文件若是utf-8编码且含有中文,控制台显示汉字乱码(原因:控制台显示字符编码是ansi);建议文件以ansi编码形式

#include <string.h>
#include "csv.h"

struct Student
{
	int  id;
	int  age;
	char sex[10];
	char name[10];
};

struct DataHandle
{
	int col;
	int row;
	struct Student stu;
};

// 列级数据处理回调函数(先处理)
void col_callback(void *s, size_t len, void *data)
{
	struct DataHandle *handle = (struct DataHandle *)data;
	char *str = malloc(len + 1);
	memset(str, 0, len + 1);
	memcpy(str, (char *)s, len);
	switch (handle->col) // 列值匹配,注意行和列都是从0开始
	{
		case 0: 
			handle->stu.id = atoi(str);
			break;
		case 1: 
			memcpy(handle->stu.name, str, len + 1);
			break;
		case 2: 
			memcpy(handle->stu.sex, str, len + 1);
			break;
		case 3:
			handle->stu.age = atoi(str);
		default:
			break;
	}
	free(str);
	// 列计数 + 1
	(handle->col)++;
}

// 行级数据处理回调函数(后处理)
void row_callback(int c, void *data)
{
	printf("%d\n", c); // 行结束符的ASCII值
	struct DataHandle *handle = (struct DataHandle *)data;
	printf("{id:%d, name:\"%s\", sex:\"%s\", age:%d}\n",
		handle->stu.id, handle->stu.name, handle->stu.sex, handle->stu.age);
	// 行计数 + 1,列计数 清零
	(handle->row)++;
	printf("row:%d col:%d\n", handle->row, handle->col);
	handle->col = 0;
}

int csv_parse_file(const char *file_path, void(*cols_callback)(void *, size_t, void *),
				   void(*rows_callback)(int c, void *), void *data)
{
	struct csv_parser conf;
	FILE *fp = NULL;
	size_t bytes_read = 0;
	size_t retval = 0;
	char buf[1024] = { 0 };
	int result = -1;

	if (csv_init(&conf, CSV_STRICT | CSV_STRICT_FINI) != 0) // 初始化
	{
		printf("failed to initialize csv parser\n");
		return result;
	}
	
	fp = fopen(file_path, "rb"); // 打开文件(二进制只读模式)
	if (fp == NULL)
	{
		fprintf(stderr, "Failed to open file %s: %s\n", file_path, strerror(errno));
		goto END;
	}
	while ((bytes_read = fread(buf, sizeof(char), sizeof(buf), fp)) > 0)
	{
		retval = csv_parse(&conf, buf, bytes_read, cols_callback, rows_callback, data);
		if (retval != bytes_read)
		{
			fprintf(stderr, "Error parsing file: %s\n", csv_strerror(csv_error(&conf)));
			goto END;
		}
	}
	
	if (0 != csv_fini(&conf, cols_callback, rows_callback, data))
	{
		goto END;
	}
	result = 0;
END:
	csv_free(&conf);
	fclose(fp);
	return result;
}

int main(int argc, const char *argv[])
{
	const char *file_path = { "student_data.csv" };
	struct DataHandle handle = { 0 };
	csv_parse_file(file_path, col_callback, row_callback, &handle);
	return 0;
}

三、反思总结#

libcsv解析流程:

  • csv_init() 初始化
  • fread() 读取数据
  • csv_parse() 解析数据
  • csv_fini() 处理最后的数据
  • csv_free() 释放内存

四、参考引用#

作者:caojun97

出处:https://www.cnblogs.com/caojun97/p/17219273.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   eiSouthBoy  阅读(1081)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu