mirror of
https://gitee.com/Lamdonn/varch.git
synced 2025-12-06 08:46:42 +08:00
284 lines
10 KiB
Markdown
284 lines
10 KiB
Markdown
## 介绍
|
||
|
||
### 什么是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对象
|
||
```c
|
||
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对象加载
|
||
```c
|
||
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对象转储
|
||
```c
|
||
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获取行、列、单元格计数
|
||
```c
|
||
unsigned int csv_row(csv_t csv);
|
||
unsigned int csv_col(csv_t csv);
|
||
unsigned int csv_cell(csv_t csv);
|
||
```
|
||
分别获取csv表格中的行列数以及非空的单元格计数。
|
||
|
||
### csv深拷贝
|
||
```c
|
||
csv_t csv_duplicate(csv_t csv);
|
||
```
|
||
根据源csv对象深拷贝出一份新的csv对象。
|
||
|
||
### csv转数组
|
||
```c
|
||
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压缩
|
||
```c
|
||
void csv_minify(csv_t csv);
|
||
```
|
||
该方法不会影响csv实际的存储内容,会将行末无效的空单元格去除掉,从而缩小存储空间。
|
||
|
||
### csv设置单元格内容
|
||
```c
|
||
int csv_set_text(csv_t csv, unsigned int row, unsigned int col, const char* text);
|
||
```
|
||
在(row, col)单元格覆盖性写入text文本,当单元格不存在的时候,也会新建单元格进行写入。
|
||
|
||
### csv获取单元格内容
|
||
```c
|
||
const char* csv_get_text(csv_t csv, unsigned int row, unsigned int col);
|
||
```
|
||
获取(row, col)单元格内容,返回NULL表示不存在这个单元格。
|
||
|
||
### csv清空单元格内容
|
||
```c
|
||
void csv_clean_text(csv_t csv, unsigned int row, unsigned int col);
|
||
```
|
||
清空(row, col)单元格内容。
|
||
|
||
### csv插入行列
|
||
```c
|
||
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删除行列
|
||
```c
|
||
int csv_delete_row(csv_t csv, unsigned int pos);
|
||
int csv_delete_col(csv_t csv, unsigned int pos);
|
||
```
|
||
删除pos位置的行或列(pos为0时,默认尾删)。
|
||
|
||
### csv移动行列
|
||
```c
|
||
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复制行列
|
||
```c
|
||
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插入单元格
|
||
```c
|
||
int csv_insert_cell(csv_t csv, unsigned int row, unsigned int col, int move_down);
|
||
```
|
||
在(row, col)的位置插入空单元格,如果指定move_down为非0后面内容向下移动,否则向右移动。
|
||
|
||
### csv删除单元格
|
||
```c
|
||
int csv_delete_cell(csv_t csv, unsigned int row, unsigned int col, int move_up);
|
||
```
|
||
删除(row, col)的位置单元格,如果指定move_up为非0后面内容向上移动,否则向左移动。
|
||
|
||
### csv复制单元格
|
||
```c
|
||
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剪切单元格
|
||
```c
|
||
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查找
|
||
```c
|
||
int csv_find(csv_t csv, const char* text, int flag, unsigned int* row, unsigned int* col);
|
||
```
|
||
在整个表格表格中查找`text`,匹配上单元格后返回1,匹配位置为(row, col)。查找到结束后,返回-1。
|
||
查找规则通过`flag`来控制
|
||
```c
|
||
#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遍历非空单元格
|
||
```c
|
||
#define csv_for_each(csv, row, col, text)
|
||
```
|
||
按行从上往下遍历所有非空单元格。
|
||
```c
|
||
const char *text = NULL;
|
||
csv_for_each(csv, row, col, text)
|
||
{
|
||
printf("[%d, %d]: %s\r\n", row, col, text);
|
||
}
|
||
```
|
||
|
||
## 参考例子
|
||
|
||
### 生成csv文件
|
||
```c
|
||
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**
|
||
```csv
|
||
ID,Name,Gender,Age,Height
|
||
20240107001,ZhangSan,Man,18,178
|
||
20240107002,LiSi,Woman,24,162
|
||
```
|
||
|
||
### 加载csv文件
|
||
同样加载csv文件 **info.csv**
|
||
```csv
|
||
ID,Name,Gender,Age,Height
|
||
20240107001,ZhangSan,Man,18,178
|
||
20240107002,LiSi,Woman,24,162
|
||
```
|
||
|
||
```c
|
||
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
|
||
```
|