📅  最后修改于: 2023-12-03 14:40:25.031000             🧑  作者: Mango
CSV(Comma Separated Values)文件是一种常见的数据存储格式,它通常用来存储简单的表格数据。在C语言中,我们可以通过读写CSV文件来实现简单的关系数据库。
在CSV文件中,每行代表一条记录,每个字段用逗号(或其他字符)分隔。例如,下面是一个简单的CSV文件:
id,name,age
1,Alice,20
2,Bob,25
3,Charlie,30
第一行通常是字段名,后面每行代表一条记录。可以看出,CSV文件类似于一个表格形式的数据,其中每一列代表一种数据类型。
在C语言中,我们可以使用fgets()
函数逐行读取CSV文件,并使用strtok()
函数解析每行中的字段。下面是一个简单的例子:
#include <stdio.h>
#include <string.h>
#define MAX_LINE_LEN 1024
#define MAX_FIELD_NUM 10
#define FIELD_DELIMITER ','
typedef struct {
int id;
char name[64];
int age;
} Person;
int main() {
FILE *fp = fopen("data.csv", "r");
if (fp == NULL) {
printf("failed to open file\n");
return 1;
}
char line[MAX_LINE_LEN];
char *fields[MAX_FIELD_NUM];
int row = 0;
while (fgets(line, sizeof(line), fp) != NULL) {
int col = 0;
for (char *field = strtok(line, ",\n"); field != NULL; field = strtok(NULL, ",\n")) {
fields[col++] = field;
}
if (row > 0) {
Person person;
person.id = atoi(fields[0]);
strcpy(person.name, fields[1]);
person.age = atoi(fields[2]);
printf("id=%d, name=%s, age=%d\n", person.id, person.name, person.age);
}
row++;
}
fclose(fp);
return 0;
}
上述例子中,我们定义了一个Person
结构体表示CSV文件中的一条记录,使用fgets()
函数逐行读取文件,并使用strtok()
函数解析每行中的字段。由于第一行是字段名,我们可以通过row
变量的值来判断当前行是否是第一行,再决定是否要将字段的值读取到对应的Person
结构体中。
与读取CSV文件相反,我们同样可以使用fprintf()
函数将一条记录写入到CSV文件中。下面是一个简单的例子:
#include <stdio.h>
#define CSV_FILE "data.csv"
typedef struct {
int id;
char name[64];
int age;
} Person;
int main() {
FILE *fp = fopen(CSV_FILE, "a");
if (fp == NULL) {
printf("failed to open file\n");
return 1;
}
Person person = {4, "David", 35};
fprintf(fp, "%d,%s,%d\n", person.id, person.name, person.age);
fclose(fp);
return 0;
}
上述例子中,我们同样定义了一个Person
结构体表示要写入到CSV文件中的一条记录,使用fprintf()
函数将这条记录写入到CSV文件中。
通过读取和写入CSV文件,我们可以实现一个简单的关系数据库。例如,我们可以定义一个PersonList
结构体来表示一个人员名单:
#include <stdio.h>
#include <string.h>
#define MAX_LINE_LEN 1024
#define MAX_FIELD_NUM 10
#define FIELD_DELIMITER ','
#define CSV_FILE "person_list.csv"
typedef struct {
int id;
char name[64];
int age;
} Person;
typedef struct {
Person persons[100];
int count;
} PersonList;
void load_person_list(PersonList *person_list) {
FILE *fp = fopen(CSV_FILE, "r");
if (fp == NULL) {
printf("failed to open file\n");
return;
}
char line[MAX_LINE_LEN];
char *fields[MAX_FIELD_NUM];
int row = 0;
while (fgets(line, sizeof(line), fp) != NULL) {
int col = 0;
for (char *field = strtok(line, ",\n"); field != NULL; field = strtok(NULL, ",\n")) {
fields[col++] = field;
}
if (row > 0) {
Person person;
person.id = atoi(fields[0]);
strcpy(person.name, fields[1]);
person.age = atoi(fields[2]);
person_list->persons[row-1] = person;
person_list->count++;
}
row++;
}
fclose(fp);
}
void save_person_list(PersonList *person_list) {
FILE *fp = fopen(CSV_FILE, "w");
if (fp == NULL) {
printf("failed to open file\n");
return;
}
fprintf(fp, "id,name,age\n");
for (int i = 0; i < person_list->count; i++) {
Person person = person_list->persons[i];
fprintf(fp, "%d,%s,%d\n", person.id, person.name, person.age);
}
fclose(fp);
}
void add_person(PersonList *person_list, Person person) {
person_list->persons[person_list->count] = person;
person_list->count++;
}
void remove_person(PersonList *person_list, int id) {
for (int i = 0; i < person_list->count; i++) {
if (person_list->persons[i].id == id) {
for (int j = i+1; j < person_list->count; j++) {
person_list->persons[j-1] = person_list->persons[j];
}
person_list->count--;
break;
}
}
}
int main() {
PersonList person_list = {0};
load_person_list(&person_list);
Person person = {4, "David", 35};
add_person(&person_list, person);
remove_person(&person_list, 2);
save_person_list(&person_list);
return 0;
}
上述代码中,我们定义了一个PersonList
结构体来表示一个人员名单,包含了人员记录数组和人员记录数量。使用load_person_list()
函数将CSV文件中的记录读取到PersonList
结构体中,使用save_person_list()
函数将PersonList
结构体中的记录保存到CSV文件中。我们同时还定义了add_person()
和remove_person()
函数来添加和删除一条记录。在程序中,我们首先调用load_person_list()
函数将CSV文件中的记录读取到person_list
变量中,然后调用add_person()
函数添加一条记录,再调用remove_person()
函数删除一条记录,最后调用save_person_list()
函数将person_list
变量中的记录保存到CSV文件中。
总之,通过读写CSV文件,我们可以实现简单的关系数据库。和传统的关系数据库相比,CSV文件具有易读易写的特点,对于一些简单的应用场景非常适用。