10 KiB
介绍
什么是CSV文件?
CSV(逗号分隔值)是一种常见的文件格式,用于存储和交换简单的数据表格。CSV文件由文本行组成,每行代表表格中的一行数据,每个数据字段之间使用逗号分隔。
CSV文件的特点
- 简单易用:CSV文件使用纯文本格式,易于创建和编辑。几乎所有的电子表格软件和文本编辑器都支持CSV文件的读写操作。
- 跨平台兼容:CSV文件是一种通用的数据交换格式,可以在不同操作系统上进行读取和处理,如Windows、Mac和Linux。
- 灵活性:CSV文件可以包含任意数量的行和列,可以存储各种类型的数据,如文本、数字和日期。
- 可读性:由于CSV文件采用纯文本格式,因此易于人类阅读和理解,也方便数据分析和处理。
CSV文件的用途
CSV文件广泛应用于数据导入、导出和交换的场景,包括:
- 数据导入和导出:CSV文件常用于将数据从一个应用程序导出到另一个应用程序,或从数据库导出到电子表格软件,反之亦然。
- 数据交换:CSV文件作为一种通用的数据交换格式,常用于不同系统之间的数据交换,如数据集成、数据同步等。
- 数据备份和存储:CSV文件可以作为一种简单的数据备份和存储格式,方便将数据以纯文本形式保存,并在需要时进行恢复。
- 数据分析和处理:CSV文件可以方便地进行数据分析和处理,可以使用各种数据分析工具(如Excel、Python等)对CSV文件进行操作和计算。
如何创建和编辑CSV文件?
创建和编辑CSV文件可以使用文本编辑器、电子表格软件或编程语言来实现。以下是一些常见的方法:
- 文本编辑器:可以使用文本编辑器(如Notepad++、Sublime Text等)创建和编辑CSV文件,按照逗号分隔每个数据字段。
- 电子表格软件:常见的电子表格软件(如Microsoft Excel、Google Sheets等)提供导入、导出和编辑CSV文件的功能。可以使用电子表格软件创建和编辑CSV文件,并保存为CSV格式。
- 编程语言:使用编程语言(如Python、Java等)可以读取、写入和处理CSV文件。许多编程语言提供了专门的CSV库和函数,方便对CSV文件进行操作和处理。
注意事项
在创建和处理CSV文件时,需要注意以下事项:
- 数据格式:确保CSV文件中的数据按照正确的格式进行存储,如日期、数字等需要按照约定的格式进行输入。
- 数据编码:根据需要选择适当的字符编码,在不同操作系统和应用程序中确保CSV文件的编码一致性。
- 数据转义:当数据字段中包含逗号、换行符等特殊字符时,需要进行适当的转义或引用,以确保数据的正确性。
C语言版CSV库
varch提供的CSV库,简便易用,能完成大部分对于表格的基础操作,包含对csv的加载和保存,针对行、列、单元格的增删改查。
接口
创建和删除csv对象
csv_t csv_create(unsigned int row, unsigned int col, const void *array);
void csv_delete(csv_t csv);
其中csv_t为csv的结构体,创建方法会生成一个指定行列的表格,同时初始化为指定的array。删除方法则删除指定的csv对象。
csv对象加载
csv_t csv_loads(const char* text);
csv_t csv_file_load(const char* filename);
csv对象可以从字符串文本中加载,也可以从文件中加载。加载成功则会返回一个csv对象,失败则返回NULL。
当csv对象加载失败的时候,可以调用int csv_error_info(int* line, int* column);函数进行定位错误。
错误类型包含
#define CSV_E_OK (0) /* no error */
#define CSV_E_MEMORY (1) /* memory allocation failed */
#define CSV_E_OPEN (2) /* fail to open file */
csv对象转储
char* csv_dumps(csv_t csv, int* len);
int csv_file_dump(csv_t csv, const char* filename);
首先csv_dumps方法,将csv对象按格式转储为字符串。*len则是转换出来的字符串长度,传入NULL时候就是不获取长度。返回值则是转换出来的字符串,这个字符串是函数分配的,在结束使用需要free掉。
csv_file_dump方法则是在csv_dumps的基础上将csv转储到文件当中,filename传入文件名,返回值为转储的长度,负值表示转储失败。
csv获取行、列、单元格计数
unsigned int csv_row(csv_t csv);
unsigned int csv_col(csv_t csv);
unsigned int csv_cell(csv_t csv);
分别获取csv表格中的行列数以及非空的单元格计数。
csv深拷贝
csv_t csv_duplicate(csv_t csv);
根据源csv对象深拷贝出一份新的csv对象。
csv转数组
int csv_to_array(csv_t csv, unsigned int o_row, unsigned int o_col, void *array, unsigned int row_size, unsigned int col_size);
以[o_row, o_col]为起点,将(row_size, col_size)大小的选区内容转到array。
csv压缩
void csv_minify(csv_t csv);
该方法不会影响csv实际的存储内容,会将行末无效的空单元格去除掉,从而缩小存储空间。
csv设置单元格内容
int csv_set_text(csv_t csv, unsigned int row, unsigned int col, const char* text);
在(row, col)单元格覆盖性写入text文本,当单元格不存在的时候,也会新建单元格进行写入。
csv获取单元格内容
const char* csv_get_text(csv_t csv, unsigned int row, unsigned int col);
获取(row, col)单元格内容,返回NULL表示不存在这个单元格。
csv清空单元格内容
void csv_clean_text(csv_t csv, unsigned int row, unsigned int col);
清空(row, col)单元格内容。
csv插入行列
int csv_insert_row(csv_t csv, unsigned int pos, const char **array, unsigned int count);
int csv_insert_col(csv_t csv, unsigned int pos, const char **array, unsigned int count);
在pos的位置插入行或列(pos为0时,默认尾插),如果指定array和count,则会把插入的行或列初始为array,count指定初始化的个数。
csv删除行列
int csv_delete_row(csv_t csv, unsigned int pos);
int csv_delete_col(csv_t csv, unsigned int pos);
删除pos位置的行或列(pos为0时,默认尾删)。
csv移动行列
int csv_move_row_to(csv_t csv, unsigned int pos, unsigned int dest);
int csv_move_col_to(csv_t csv, unsigned int pos, unsigned int dest);
将pos位置的行或列(pos为0时,默认尾删)移动到dest的位置。
csv复制行列
int csv_copy_row_to(csv_t csv, unsigned int pos, unsigned int dest);
int csv_copy_col_to(csv_t csv, unsigned int pos, unsigned int dest);
将pos位置的行或列(pos为0时,默认尾删)复制到dest的位置。
csv插入单元格
int csv_insert_cell(csv_t csv, unsigned int row, unsigned int col, int move_down);
在(row, col)的位置插入空单元格,如果指定move_down为非0后面内容向下移动,否则向右移动。
csv删除单元格
int csv_delete_cell(csv_t csv, unsigned int row, unsigned int col, int move_up);
删除(row, col)的位置单元格,如果指定move_up为非0后面内容向上移动,否则向左移动。
csv复制单元格
int csv_copy_cell_to(csv_t csv, unsigned int s_row, unsigned int s_col, unsigned int d_row, unsigned int d_col);
将(s_row, s_col)单元格内容复制到(d_row, d_col)单元格。
csv剪切单元格
int csv_cut_cell_to(csv_t csv, unsigned int s_row, unsigned int s_col, unsigned int d_row, unsigned int d_col);
将(s_row, s_col)单元格内容剪切到(d_row, d_col)单元格。
csv查找
int csv_find(csv_t csv, const char* text, int flag, unsigned int* row, unsigned int* col);
在整个表格表格中查找text,匹配上单元格后返回1,匹配位置为(row, col)。查找到结束后,返回-1。
查找规则通过flag来控制
#define CSV_F_FLAG_MatchCase (0x01) /* match case sensitive */
#define CSV_F_FLAG_MatchEntire (0x02) /* match the entire cell content */
#define CSV_F_FLAG_MatchByCol (0x04) /* match by column */
#define CSV_F_FLAG_MatchForward (0x08) /* match from back to front */
csv遍历非空单元格
#define csv_for_each(csv, row, col, text)
按行从上往下遍历所有非空单元格。
const char *text = NULL;
csv_for_each(csv, row, col, text)
{
printf("[%d, %d]: %s\r\n", row, col, text);
}
参考例子
生成csv文件
static void dump_demo(void)
{
csv_t csv;
const char *array[3][5] = {
{"ID", "Name", "Gender", "Age", "Height"},
{"20240107001", "ZhangSan", "Man", "18", "178"},
{"20240107002", "LiSi", "Woman", "24", "162"},
};
csv = csv_create(3, 5, array);
if (!csv)
{
printf("create csv fail!\r\n");
return;
}
if (csv_file_dump(csv, "info.csv") < 0)
{
printf("csv dump fail!\r\n");
}
else
{
printf("csv dump success!\r\n");
}
csv_delete(csv);
}
转储的文件 info.csv
ID,Name,Gender,Age,Height
20240107001,ZhangSan,Man,18,178
20240107002,LiSi,Woman,24,162
加载csv文件
同样加载csv文件 info.csv
ID,Name,Gender,Age,Height
20240107001,ZhangSan,Man,18,178
20240107002,LiSi,Woman,24,162
static void load_demo(void)
{
csv_t csv;
csv = csv_file_load("info.csv");
if (!csv)
{
printf("csv load fail!\r\n");
return;
}
unsigned int row, col;
const char *text = NULL;
csv_for_each(csv, row, col, text)
{
printf("[%u, %u]: %s\r\n", row, col, text);
}
csv_delete(csv);
}
运行结果:
[1, 1]: ID
[1, 2]: Name
[1, 3]: Gender
[1, 4]: Age
[1, 5]: Height
[2, 1]: 20240107001
[2, 2]: ZhangSan
[2, 3]: Man
[2, 4]: 18
[2, 5]: 178
[3, 1]: 20240107002
[3, 2]: LiSi
[3, 3]: Woman
[3, 4]: 24
[3, 5]: 162