📜  C中CSV文件的关系数据库(1)

📅  最后修改于: 2023-12-03 15:30:14.320000             🧑  作者: Mango

C中CSV文件的关系数据库

本文将介绍如何在C语言中使用CSV文件实现关系数据库的基本操作,包括创建数据库,创建表,插入数据以及查询数据等操作。在本文中,我们将使用libcsv库来处理CSV文件。另外,我们将使用SQLite来存储数据库数据。

创建数据库

首先,我们需要创建一个空的数据库文件,以便在其中存储表和数据。我们可以使用SQLite来创建一个空的数据库文件,代码如下:

#include <sqlite3.h>

int main() {
    sqlite3 *db;
    int rc = sqlite3_open("test.db", &db);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return 1;
    }

    sqlite3_close(db);
    return 0;
}

上述代码创建了一个名为test.db的空数据库文件。如果在打开数据库文件时出现错误,我们将显示一个错误信息并退出程序。

创建表

在创建表之前,我们需要定义表的结构,即表的列名和列类型。接下来我们可以使用libcsv来读取包含表结构的CSV文件,并使用SQLite的API创建表。具体代码如下:

#include <csv.h>
#include <stdio.h>
#include <string.h>
#include <sqlite3.h>

void create_table(sqlite3 *db, const char *name, csv_parser *parser) {
    // Get number of columns
    int n_cols = csv_parser_get_num_cols(parser);

    // Build list of column names and types
    char **columns = malloc(n_cols * sizeof(char *));
    char **types = malloc(n_cols * sizeof(char *));
    for (int i = 0; i < n_cols; i++) {
        csv_parser_get_col_info(parser, i, &columns[i], &types[i]);
    }

    // Build SQL statement
    char *sql = malloc(1024);
    strcpy(sql, "CREATE TABLE ");
    strcat(sql, name);
    strcat(sql, " (");
    for (int i = 0; i < n_cols; i++) {
        strcat(sql, "'");
        strcat(sql, columns[i]);
        strcat(sql, "' ");
        strcat(sql, types[i]);
        if (i < n_cols - 1) {
            strcat(sql, ",");
        }
    }
    strcat(sql, ")");

    // Execute SQL statement
    char *errmsg;
    int rc = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "Error creating table: %s\n", errmsg);
        sqlite3_free(errmsg);
    }

    // Cleanup
    free(columns);
    free(types);
    free(sql);
}

int main() {
    // Open CSV file
    FILE *fp = fopen("customers.csv", "r");
    if (fp == NULL) {
        fprintf(stderr, "Cannot open CSV file\n");
        return 1;
    }

    // Create CSV parser
    csv_parser *parser = csv_parser_new();
    csv_init(parser, CSV_APPEND_NULL);

    // Parse CSV file
    char buf[1024];
    size_t bytes_read;
    while ((bytes_read = fread(buf, 1, 1024, fp)) > 0) {
        csv_parse(parser, buf, bytes_read, NULL, NULL, NULL, NULL);
    }
    csv_fini(parser, NULL, NULL, NULL);
    csv_parser_free(parser);

    // Close CSV file
    fclose(fp);

    // Create database
    sqlite3 *db;
    int rc = sqlite3_open("test.db", &db);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return 1;
    }

    // Create table
    create_table(db, "customers", parser);

    // Close database
    sqlite3_close(db);

    return 0;
}

上述代码已经实现了创建表的功能。在上述代码中,我们定义了一个create_table函数,该函数将读取包含表结构的CSV文件,并在sqlite3数据库中创建一个表。具体来说,我们将使用csv_parser_get_num_cols函数获取列数,使用csv_parser_get_col_info获取列的信息,使用sqlite3_exec函数执行CREATE TABLE语句。

插入数据

插入数据是关系数据库操作中最常见的操作之一。对于CSV文件,我们可以使用libcsv库读取数据行,并使用SQLite的API将数据插入到数据库中。具体代码如下:

#include <csv.h>
#include <stdio.h>
#include <string.h>
#include <sqlite3.h>

void insert_data(sqlite3 *db, const char *table_name, csv_parser *parser) {
    // Get number of columns
    int n_cols = csv_parser_get_num_cols(parser);

    // Build list of column names
    char **columns = malloc(n_cols * sizeof(char *));
    for (int i = 0; i < n_cols; i++) {
        csv_parser_get_col_info(parser, i, &columns[i], NULL);
    }

    // Build SQL statement
    char *sql = malloc(1024);
    strcpy(sql, "INSERT INTO ");
    strcat(sql, table_name);
    strcat(sql, " (");
    for (int i = 0; i < n_cols; i++) {
        strcat(sql, "'");
        strcat(sql, columns[i]);
        strcat(sql, "'");
        if (i < n_cols - 1) {
            strcat(sql, ",");
        }
    }
    strcat(sql, ") VALUES (");
    for (int i = 0; i < n_cols; i++) {
        strcat(sql, "?");
        if (i < n_cols - 1) {
            strcat(sql, ",");
        }
    }
    strcat(sql, ")");

    // Prepare statement
    sqlite3_stmt *stmt;
    int rc = sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, NULL);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "Error preparing statement: %s\n", sqlite3_errmsg(db));
        goto cleanup;
    }

    // Insert data
    char **row;
    int n_row;
    while ((row = csv_parser_get_row(parser, &n_row)) != NULL) {
        if (n_row == n_cols) {
            for (int i = 0; i < n_cols; i++) {
                sqlite3_bind_text(stmt, i + 1, row[i], strlen(row[i]), SQLITE_STATIC);
            }
            rc = sqlite3_step(stmt);
            if (rc != SQLITE_DONE) {
                fprintf(stderr, "Error inserting row: %s\n", sqlite3_errmsg(db));
                goto cleanup;
            }
            sqlite3_reset(stmt);
        }
        csv_parser_free_row(row);
    }

cleanup:
    sqlite3_finalize(stmt);
    free(columns);
    free(sql);
}

int main() {
    // Open CSV file
    FILE *fp = fopen("customers.csv", "r");
    if (fp == NULL) {
        fprintf(stderr, "Cannot open CSV file\n");
        return 1;
    }

    // Create CSV parser
    csv_parser *parser = csv_parser_new();
    csv_init(parser, CSV_APPEND_NULL);

    // Parse CSV file
    char buf[1024];
    size_t bytes_read;
    while ((bytes_read = fread(buf, 1, 1024, fp)) > 0) {
        csv_parse(parser, buf, bytes_read, NULL, NULL, NULL, NULL);
    }
    csv_fini(parser, NULL, NULL, NULL);
    csv_parser_free(parser);

    // Close CSV file
    fclose(fp);

    // Open database
    sqlite3 *db;
    int rc = sqlite3_open("test.db", &db);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return 1;
    }

    // Insert data
    insert_data(db, "customers", parser);

    // Close database
    sqlite3_close(db);

    return 0;
}

上述代码已经实现了将数据插入到数据库中的功能。在上述代码中,我们定义了一个insert_data函数,该函数将读取CSV文件中的数据行,并将数据插入到sqlite3数据库中。具体来说,我们将使用sqlite3_prepare_v2函数准备INSERT语句,使用sqlite3_bind_text函数将数据绑定到语句中,使用sqlite3_step函数执行INSERT语句,并使用sqlite3_reset函数重置语句以准备下一条INSERT语句的执行。

查询数据

查询数据是关系数据库操作中最常见的操作之一。我们可以使用SQLite的API来查询数据,并使用libcsv库将查询结果输出到CSV文件中。具体代码如下:

#include <csv.h>
#include <stdio.h>
#include <sqlite3.h>

void query_data(sqlite3 *db, const char *table_name, const char *output_file) {
    // Build SQL statement
    char *sql = malloc(1024);
    sprintf(sql, "SELECT * FROM %s", table_name);

    // Prepare statement
    sqlite3_stmt *stmt;
    int rc = sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, NULL);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "Error preparing statement: %s\n", sqlite3_errmsg(db));
        goto cleanup;
    }

    // Open CSV file
    FILE *fp = fopen(output_file, "w");
    if (fp == NULL) {
        fprintf(stderr, "Cannot open output file\n");
        goto cleanup;
    }

    // Write header row to CSV file
    int n_cols = sqlite3_column_count(stmt);
    for (int i = 0; i < n_cols; i++) {
        const char *col_name = sqlite3_column_name(stmt, i);
        if (i > 0) {
            fprintf(fp, ",");
        }
        fprintf(fp, "%s", col_name);
    }
    fprintf(fp, "\n");

    // Write data rows to CSV file
    while (sqlite3_step(stmt) == SQLITE_ROW) {
        for (int i = 0; i < n_cols; i++) {
            const char *col_value = (const char *)sqlite3_column_text(stmt, i);
            if (i > 0) {
                fprintf(fp, ",");
            }
            fprintf(fp, "\"%s\"", col_value);
        }
        fprintf(fp, "\n");
    }

    // Close CSV file
    fclose(fp);

cleanup:
    sqlite3_finalize(stmt);
    free(sql);
}

int main() {
    // Open database
    sqlite3 *db;
    int rc = sqlite3_open("test.db", &db);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return 1;
    }

    // Query data
    query_data(db, "customers", "customers_output.csv");

    // Close database
    sqlite3_close(db);

    return 0;
}

上述代码已经实现了查询数据的功能。在上述代码中,我们定义了一个query_data函数,该函数将执行SELECT语句,并将查询结果输出到指定的CSV文件中。具体来说,我们将使用sqlite3_prepare_v2函数准备SELECT语句,使用sqlite3_step函数执行SELECT语句,并将查询结果输出到CSV文件中。

结论

本文介绍了如何在C语言中使用CSV文件实现关系数据库的基本操作,包括创建数据库,创建表,插入数据以及查询数据等操作。在本文中,我们使用了libcsv库来处理CSV文件,使用了SQLite来存储数据库数据。在实现过程中,我们使用了libcsv库的API来读取数据行,并使用了SQLite的API来执行SQL语句。同时,我们还介绍了如何将查询结果输出到CSV文件中。