在日常 C++ 开发中,针对中小型结构化数据(如用户信息、商品列表)的管理,往往不需要引入重型数据库或复杂网络库。本文将介绍我(董翔)开发的一个轻量级 C++ 数据管理框架,也就是 MiniDataX,该框架基于原生 C++ 实现,包含结构化数据定义、跨文件数据共享、异步请求模拟、MySQL 风格表格展示四大核心功能,无第三方依赖,可直接集成到项目中使用。

一、框架核心定位与适用场景

1. 核心定位

  • 轻量级:纯 C++ 原生实现,无任何外部依赖(无需数据库、网络库);
  • 模块化:数据存储、业务逻辑、请求处理、可视化展示完全解耦;
  • 易扩展:支持自定义数据结构,适配不同业务场景(用户、商品、订单等)。

2. 适用场景

  • 中小型结构化数据管理(数据量 1000 条以内);
  • 需模拟网络请求的 Demo 或测试项目;
  • 嵌入式设备、桌面工具等轻量化数据展示场景;
  • 教学场景下的 C++ 模块化、异步编程实践。

二、框架文件结构

框架共包含 5 个核心文件,各文件职责清晰,便于维护和扩展:

mini-data-framework/
├─ util.h          // 核心配置文件:数据结构定义、全局变量声明、接口声明
├─ data.db         // 数据存储文件:数据初始化、持久化(自定义.db后缀,本质C++源文件)
├─ promise.h       // 异步请求核心:Promise类实现,支持异步回调与错误处理
├─ table.cpp       // 可视化模块:MySQL风格表格打印实现
└─ main.cpp        // 业务入口:请求发起、逻辑串联、框架调用示例

三、核心文件实现详解

1. util.h:框架配置核心

该文件是框架的 “契约中心”,定义数据结构、全局容器和核心接口,使用者只需修改此文件即可适配自身业务。

#ifndef UTIL_H
#define UTIL_H

#include <vector>
#include <string>

// 1. 自定义数据结构(使用者需根据业务修改)
// 示例:商品数据结构(可替换为用户、订单等结构)
typedef struct {
    std::string name;   // 商品名称
    float price;        // 商品价格(单位:元)
    int stock;          // 库存数量
    std::string brand;  // 品牌
} Product;

// 2. 全局数据容器声明(跨文件共享数据,定义在data.db中)
extern std::vector<Product> g_product_list;

// 3. 核心接口声明(实现分别在data.db、table.cpp中)
// 数据初始化:将初始数据加载到全局容器
void data_init();

// 数据查询:模拟数据库查询,根据URL匹配数据(支持扩展多接口)
std::vector<Product> data_query(const std::string& url);

// 表格打印:将数据以MySQL风格展示
void print_table(const std::vector<Product>& data);

#endif // UTIL_H

2. data.db:数据存储模块

自定义.db后缀标识 “数据文件”,本质是 C++ 源文件,负责数据初始化和持久化(示例含基础初始化,可扩展文件读写)。

#include "util.h"
#include <fstream>

// 全局数据容器定义(与util.h中extern声明对应)
std::vector<Product> g_product_list;

// 初始数据(模拟数据库表数据,可根据业务修改)
const Product g_init_products[] = {
    {"iPhone 15", 5999.0f, 120, "Apple"},
    {"Mate 60 Pro", 6499.0f, 80, "Huawei"},
    {"Xiaomi 14", 4299.0f, 200, "Xiaomi"},
    {"OnePlus 12", 4599.0f, 150, "OnePlus"}
};

// 数据初始化:将初始数据加载到全局容器
void data_init() {
    int init_count = sizeof(g_init_products) / sizeof(g_init_products[0]);
    for (int i = 0; i < init_count; i++) {
        g_product_list.push_back(g_init_products[i]);
    }
    // 扩展:可添加从本地文件加载数据的逻辑(如data.db.dat)
}

// 数据查询:模拟网络接口路由(支持扩展多URL,如/api/user、/api/order)
std::vector<Product> data_query(const std::string& url) {
    // 匹配商品查询接口(可扩展其他接口)
    if (url == "/api/product") {
        return g_product_list;
    }
    // 未匹配接口返回空数据(触发错误回调)
    return std::vector<Product>();
}

3. promise.h:异步请求核心

实现前端 Promise 风格的异步回调机制,支持成功 / 失败回调,模拟网络请求的异步特性。

#ifndef PROMISE_H
#define PROMISE_H

#include <functional>
#include <utility>

// 空类型标识:用于无额外错误信息的场景
struct Undefined {};

// Promise类模板:SuccessT-成功返回类型,FailT-失败返回类型
template <typename SuccessT, typename FailT = Undefined>
class Promise {
public:
    // 回调函数类型定义
    using ResolveFunc = std::function<void(SuccessT)>;
    using RejectFunc = std::function<void(FailT)>;

    // 构造函数:接收执行器(包含异步逻辑)
    template <typename Executor>
    Promise(Executor&& executor) : m_state(PENDING) {
        // 包装resolve/reject,传递给执行器
        auto resolve = [this](SuccessT value) {
            if (m_state != PENDING) return;
            m_state = FULFILLED;
            m_success_val = std::move(value);
            // 触发成功回调
            if (m_resolve_func) m_resolve_func(m_success_val);
        };

        auto reject = [this](FailT value) {
            if (m_state != PENDING) return;
            m_state = REJECTED;
            m_fail_val = std::move(value);
            // 触发失败回调
            if (m_reject_func) m_reject_func(m_fail_val);
        };

        // 执行异步逻辑(如模拟网络请求延迟)
        executor(std::move(resolve), std::move(reject));
    }

    // then方法:注册成功/失败回调
    Promise& then(ResolveFunc resolve_func, RejectFunc reject_func) {
        m_resolve_func = std::move(resolve_func);
        m_reject_func = std::move(reject_func);

        // 处理同步完成场景(如无网络延迟)
        if (m_state == FULFILLED && m_resolve_func) {
            m_resolve_func(m_success_val);
        } else if (m_state == REJECTED && m_reject_func) {
            m_reject_func(m_fail_val);
        }

        return *this;
    }

private:
    // Promise状态: pending-等待,fulfilled-成功,rejected-失败
    enum State { PENDING, FULFILLED, REJECTED } m_state;
    SuccessT m_success_val;  // 成功返回值
    FailT m_fail_val;        // 失败返回值
    ResolveFunc m_resolve_func;  // 成功回调
    RejectFunc m_reject_func;    // 失败回调
};

#endif // PROMISE_H

4. table.cpp:可视化模块

实现 MySQL 风格的表格打印,支持自动列对齐、表头自定义,数据展示直观清晰。

#include "util.h"
#include <iostream>
#include <iomanip>

// 辅助函数:计算字符串长度(解决中文乱码问题,英文场景可简化)
int str_length(const std::string& str) {
    int len = 0;
    for (char c : str) {
        len += (c >= 0 && c <= 127) ? 1 : 2;  // 中文占2字符,英文占1字符
    }
    return len;
}

// 打印分隔线(根据列宽动态生成)
void print_separator(const std::vector<int>& col_widths) {
    std::cout << "+";
    for (int width : col_widths) {
        std::cout << std::string(width + 2, '-') << "+";
    }
    std::cout << std::endl;
}

// 核心:打印MySQL风格表格
void print_table(const std::vector<Product>& data) {
    if (data.empty()) {
        std::cout << "Empty result set" << std::endl;
        return;
    }

    // 1. 定义表头与列宽(需与数据结构字段对应)
    std::vector<std::string> headers = {"Product Name", "Price (Yuan)", "Stock", "Brand"};
    std::vector<int> col_widths = {
        12,  // Product Name列宽
        14,  // Price列宽
        6,   // Stock列宽
        8    // Brand列宽
    };

    // 2. 打印表头
    print_separator(col_widths);
    std::cout << "|";
    for (int i = 0; i < headers.size(); i++) {
        // 居中对齐(可改为左对齐:left)
        std::cout << " " << std::setw(col_widths[i]) << std::left << headers[i] << " |";
    }
    std::cout << std::endl;
    print_separator(col_widths);

    // 3. 打印数据行
    for (const auto& item : data) {
        std::cout << "|";
        // 商品名称(左对齐)
        std::cout << " " << std::setw(col_widths[0]) << std::left << item.name << " |";
        // 价格(保留1位小数,右对齐)
        std::cout << " " << std::setw(col_widths[1]-1) << std::right << std::fixed << std::setprecision(1) << item.price << " |";
        // 库存(右对齐)
        std::cout << " " << std::setw(col_widths[2]) << std::right << item.stock << " |";
        // 品牌(左对齐)
        std::cout << " " << std::setw(col_widths[3]) << std::left << item.brand << " |";
        std::cout << std::endl;
    }

    print_separator(col_widths);

    // 4. 打印数据统计
    std::cout << data.size() << " rows in set" << std::endl;
}

5. main.cpp:业务入口示例

演示框架的完整调用流程:初始化数据→发起异步请求→处理回调(成功打印表格 / 失败提示)。

#include "util.h"
#include "promise.h"
#include <iostream>

// 模拟网络请求:返回Promise对象(异步逻辑封装)
Promise<std::vector<Product>, Undefined> send_request(const std::string& url) {
    return Promise<std::vector<Product>, Undefined>([&](auto resolve, auto reject) {
        // 模拟网络请求延迟(可注释,直接同步返回)
        // std::this_thread::sleep_for(std::chrono::seconds(1));
        
        // 调用数据查询接口
        std::vector<Product> result = data_query(url);
        if (!result.empty()) {
            // 请求成功:返回查询结果
            resolve(result);
        } else {
            // 请求失败:返回空错误(Undefined)
            reject(Undefined());
        }
    });
}

int main() {
    // 1. 初始化数据(加载初始商品数据)
    data_init();
    std::cout << "Data initialized successfully!" << std::endl;

    // 2. 发起异步请求(示例1:请求存在的接口)
    std::cout << "\nRequesting /api/product..." << std::endl;
    send_request("/api/product")
    .then(
        // 成功回调:打印表格
        [](std::vector<Product> data) {
            print_table(data);
        },
        // 失败回调:提示错误
        [](Undefined) {
            std::cout << "Request failed: URL not found!" << std::endl;
        }
    );

    // 3. 发起异步请求(示例2:请求不存在的接口,触发失败回调)
    std::cout << "\nRequesting /api/order..." << std::endl;
    send_request("/api/order")
    .then(
        [](std::vector<Product> data) {
            print_table(data);
        },
        [](Undefined) {
            std::cout << "Request failed: URL not found!" << std::endl;
        }
    );

    return 0;
}

四、框架编译与运行

1. 编译命令(GCC/Clang)

由于.db文件本质是 C++ 源文件,编译时需将其与其他文件一同编译:

# 编译所有源文件,生成可执行文件mini-framework
g++ main.cpp data.db table.cpp -o mini-framework -std=c++11

2. 运行效果

Data initialized successfully!

Requesting /api/product...
+----------------------+------------------+--------+----------+
| Product Name         | Price (Yuan)     | Stock  | Brand    |
+----------------------+------------------+--------+----------+
| iPhone 15            |           5999.0 |    120 | Apple    |
| Mate 60 Pro          |           6499.0 |     80 | Huawei   |
| Xiaomi 14            |           4299.0 |    200 | Xiaomi   |
| OnePlus 12           |           4599.0 |    150 | OnePlus  |
+----------------------+------------------+--------+----------+
4 rows in set

Requesting /api/order...
Request failed: URL not found!

五、框架扩展指南

1. 适配自定义数据(如用户信息)

  1. 修改util.h中的Product结构体为User
typedef struct {
    std::string id;      // 用户ID
    std::string name;    // 用户名
    int age;             // 年龄
    std::string email;   // 邮箱
} User;
  1. 更新data.db中的初始数据和全局容器(g_user_list);
  2. 调整table.cpp的表头、列宽和数据打印逻辑,适配User字段。

2. 扩展持久化功能(本地文件读写)

data.db中添加文件读写函数,支持数据持久化到本地(如user_data.dat):

// 从文件加载数据
void load_from_file(const std::string& filename) {
    std::ifstream file(filename);
    User user;
    while (file >> user.id >> user.name >> user.age >> user.email) {
        g_user_list.push_back(user);
    }
    file.close();
}

// 保存数据到文件
void save_to_file(const std::string& filename) {
    std::ofstream file(filename);
    for (const auto& user : g_user_list) {
        file << user.id << " " << user.name << " " << user.age << " " << user.email << std::endl;
    }
    file.close();
}

3. 增加多接口支持

data.dbdata_query函数中添加新 URL 路由,支持多业务接口:

std::vector<User> data_query(const std::string& url) {
    if (url == "/api/user") {
        return g_user_list;  // 用户接口
    } else if (url == "/api/user/vip") {
        // 筛选VIP用户(扩展业务逻辑)
        std::vector<User> vip_users;
        for (const auto& user : g_user_list) {
            if (user.age > 25) {  // 示例:年龄>25视为VIP
                vip_users.push_back(user);
            }
        }
        return vip_users;
    }
    return std::vector<User>();
}

六、总结

本框架以 “轻量化、模块化、易扩展” 为核心,用原生 C++ 实现了结构化数据管理的完整流程。通过自定义数据结构、异步请求封装和可视化展示,既满足了中小型数据的管理需求,又避免了重型依赖带来的复杂性。

框架的核心优势在于 “配置简单、上手快”,开发者只需修改util.hdata.db即可适配自身业务,无需关注 Promise 异步机制和表格打印的底层实现,大幅降低了轻量化数据管理场景的开发成本。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐