varch/doc/csv.md
2024-07-21 19:02:13 +08:00

284 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 介绍
### 什么是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则会把插入的行或列初始为arraycount指定初始化的个数。
### 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
```