实现功能:
程序中struct数据结构转化为json文件保存
- 1.将程序中的struct数据集合保存成json格式。每次测试需要进行保存的数据可以生成一个新的json文件,用来传输。
例如:
c
//定义需要
typedef struct _PModelJsonTest3
{
std::string Test3Num1;
int Test3Num2;
double Test3Num3;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(_PModelJsonTest3, Test3Num1, Test3Num2, Test3Num3)
}PModelJsonTest3;
在程序中调用
c
//测试将数据类转化为json文件
CDataClassToJson converter;
///测试将数据类转化为json文件
CDataClassToJson converter;/ 示例2: 使用PModel数据类
PModelJsonTest3 P2model3;
P2model3.Test3Num1 = "string";
P2model3.Test3Num2 = 222222;
P2model3.Test3Num3 = 333333;
if (converter.ConvertToJsonFile(P2model3, CreateCodeFileName, _T("Pro2"), _T("PModelJsonTest3"))) {
AfxMessageBox(_T("PModelJsonTest3转换成功!"));
}
else
{
AfxMessageBox(_T("PModelJsonTest3转换失败!"));
}
生成的json文件格式:
c
{
"Pro2": {
"PModelJsonTest3": {
"Test3Num1": "string",
"Test3Num2": 222222,
"Test3Num3": 333333.0
}
}
}
DB数据库的操作
- 1.初始化传入一个作为模板的json文件,会根据这个模板json文件的格式生成对应的数据库表【如果监测到数据库存在,或直接打开,之前的记录不会覆盖】
例如:类似生成Pro2,添加Pro1和Pro3,会生成一下DB数据结构:
调用:
c
UpdateData();
//这个需要定义在对话框类中
CDynamicJsonSQLiteDB db;
if (db.InitializeDBFromJson(_T(filePathDir+ uiData_DBInitJsonFileName))) {
AfxMessageBox(_T("数据库初始化成功!数据库路径: ") + db.GetDBPath());
CString strInfo;
strInfo.Format(_T("当前记录数量: %d"), db.GetRecordCount());
AfxMessageBox(strInfo);
}
else {
AfxMessageBox(_T("初始化失败: ") + db.GetLastError());
return;
}
- 2.添加接口,传入一组数据json文件会在数据库中添加新的一组数据【此文件结构需要跟初始化json的结构相同,否则会报错】
c
UpdateData();
// 2. 添加数据记录(传入JSON文件名)
if (db.AddDataRecord(_T(filePathDir + uiData_DBAddJsonFileName))) {
AfxMessageBox(_T("数据记录1添加成功!"));
}
else {
AfxMessageBox(_T("数据记录添加失败: ") + db.GetLastError());
}
// 显示当前记录数量
CString strCount;
strCount.Format(_T("当前总记录数: %d"), db.GetRecordCount());
AfxMessageBox(strCount);
- 3.传入需要导出的序列号,导出数据库中的改数据,为一个json文件
c
UpdateData();
CString filePathDir = "D:\\DB\\DBJson_Test\\";
if (db.ExportDataToJson(uiData_DBOutDBNum, _T(filePathDir + "DB_OutJson.json"))) {
CString strCount;
strCount.Format(_T("第 %d 条记录导出成功!"), uiData_DBOutDBNum);
AfxMessageBox(strCount);
}
else {
CString strCount;
strCount.Format(_T("第%d条记录导出失败: !"), uiData_DBOutDBNum);
AfxMessageBox(strCount + db.GetLastError());
}
- 4.操作完成后关闭数据库
c
db.CloseDB();
以下为程序中的数据结构转json实现接口:
注意需要导入使用 nlohmann/json 库,可以从官网下载json.hpp,直接放入程序中引用即可
CDataClassToJson.h
cpp
#pragma once
#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <type_traits>
#include <fstream>
#include <sstream>
#include "json.hpp" // 使用 nlohmann/json 库
using json = nlohmann::json;
#ifdef UNICODE
#include <windows.h>
#endif
// 反射辅助宏
#define DEFINE_FIELD(Class, Field) \
std::make_pair(#Field, [](const Class& obj) -> std::string { \
if constexpr (std::is_arithmetic_v<decltype(obj.Field)>) { \
return std::to_string(obj.Field); \
} else if constexpr (std::is_same_v<decltype(obj.Field), std::string>) { \
return "\"" + obj.Field + "\""; \
} else if constexpr (std::is_same_v<decltype(obj.Field), const char*>) { \
return "\"" + std::string(obj.Field) + "\""; \
} else { \
return "\"" + std::to_string(obj.Field) + "\""; \
} \
})
// 通用的JSON文件管理器
class CDataClassToJson
{
public:
CDataClassToJson();
virtual ~CDataClassToJson();
// 辅助函数
CString GetLastError() const { return m_strLastError; }
BOOL FileExists(LPCTSTR lpszFilePath);
CString ReadFileToString(LPCTSTR lpszFilePath);
BOOL WriteStringToFile(LPCTSTR lpszFilePath, LPCTSTR lpszContent);
private:
CString m_strLastError;
// 内部方法
BOOL EnsureJsonFileExists(LPCTSTR lpszJsonFilePath, LPCTSTR lpszProgramName);
BOOL UpdateJsonFileWithData(LPCTSTR lpszJsonFilePath,
LPCTSTR lpszProgramName,
LPCTSTR lpszClassName,
const std::map<std::string, std::string>& fieldValues);
// 字符串转换
std::string CStringToStdString(LPCTSTR lpszStr);
CString StdStringToCString(const std::string& str);
public:
//// 主要接口:将数据类转换为JSON文件
//在C++中,模板函数的定义必须在使用时可见
// 序列化到JSON文件 - 支持同一程序下多类名数据合并,不覆盖同类名数据
template<typename T>
static BOOL ConvertToJsonFile(const T& dataObj,
LPCTSTR lpszJsonFilePath,
LPCTSTR lpszProgramName,
LPCTSTR lpszClassName = nullptr) {
try {
json root;
// 如果文件已存在,先读取现有数据
std::ifstream ifs(TCHARToString(lpszJsonFilePath));
if (ifs.is_open()) {
ifs >> root;
ifs.close();
}
std::string programName = TCHARToString(lpszProgramName);
std::string className = TCHARToString(lpszClassName);
// 如果程序节点不存在,创建它
if (!root.contains(programName)) {
root[programName] = json::object();
}
// 如果类名节点不存在,创建它
if (!root[programName].contains(className)) {
root[programName][className] = json::object();
}
// 合并数据:将新数据合并到现有类数据中
MergeJsonData(root[programName][className], dataObj);
// 写回文件
std::ofstream ofs(TCHARToString(lpszJsonFilePath));
if (!ofs.is_open()) {
return FALSE;
}
ofs << root.dump(4);
return TRUE;
}
catch (const std::exception& e) {
std::cerr << "ConvertToJsonFile error: " << e.what() << std::endl;
return FALSE;
}
catch (...) {
std::cerr << "ConvertToJsonFile unknown error" << std::endl;
return FALSE;
}
}
//// 从JSON文件读取到数据类
// 从JSON文件反序列化指定类的数据
template<typename T>
static BOOL ConvertFromJsonFile(T& dataObj,
LPCTSTR lpszJsonFilePath,
LPCTSTR lpszProgramName,
LPCTSTR lpszClassName = nullptr) {
try {
std::ifstream ifs(TCHARToString(lpszJsonFilePath));
if (!ifs.is_open()) {
return FALSE;
}
json root;
ifs >> root;
std::string programName = TCHARToString(lpszProgramName);
std::string className = TCHARToString(lpszClassName);
if (!root.contains(programName)) {
return FALSE;
}
if (!root[programName].contains(className)) {
return FALSE;
}
// 只反序列化指定类的数据
dataObj = root[programName][className].get<T>();
return TRUE;
}
catch (const std::exception& e) {
std::cerr << "ConvertFromJsonFile error: " << e.what() << std::endl;
return FALSE;
}
catch (...) {
std::cerr << "ConvertFromJsonFile unknown error" << std::endl;
return FALSE;
}
}
// 从JSON文件反序列化整个程序的所有类数据
template<typename T>
static BOOL ConvertAllClassesFromJsonFile(std::map<std::string, T>& classDataMap,
LPCTSTR lpszJsonFilePath,
LPCTSTR lpszProgramName) {
try {
std::ifstream ifs(TCHARToString(lpszJsonFilePath));
if (!ifs.is_open()) {
return FALSE;
}
json root;
ifs >> root;
std::string programName = TCHARToString(lpszProgramName);
if (!root.contains(programName)) {
return FALSE;
}
classDataMap.clear();
for (auto it = root[programName].begin(); it != root[programName].end(); ++it) {
T data;
data = it.value().get<T>();
classDataMap[it.key()] = data;
}
return TRUE;
}
catch (const std::exception& e) {
std::cerr << "ConvertAllClassesFromJsonFile error: " << e.what() << std::endl;
return FALSE;
}
catch (...) {
std::cerr << "ConvertAllClassesFromJsonFile unknown error" << std::endl;
return FALSE;
}
}
// 序列化到字符串 - 支持合并
template<typename T>
static std::string ConvertToJsonString(const T& dataObj,
const std::string& existingJsonStr,
LPCTSTR lpszProgramName,
LPCTSTR lpszClassName = nullptr) {
try {
json root;
if (!existingJsonStr.empty()) {
root = json::parse(existingJsonStr);
}
std::string programName = TCHARToString(lpszProgramName);
std::string className = TCHARToString(lpszClassName);
if (!root.contains(programName)) {
root[programName] = json::object();
}
if (!root[programName].contains(className)) {
root[programName][className] = json::object();
}
MergeJsonData(root[programName][className], dataObj);
return root.dump(4);
}
catch (const std::exception& e) {
std::cerr << "ConvertToJsonString error: " << e.what() << std::endl;
return "";
}
}
// 新增:获取整个JSON文件内容
static std::string ReadJsonFile(LPCTSTR lpszJsonFilePath) {
try {
std::ifstream ifs(TCHARToString(lpszJsonFilePath));
if (!ifs.is_open()) {
return "{}";
}
std::string content((std::istreambuf_iterator<char>(ifs)),
std::istreambuf_iterator<char>());
return content;
}
catch (...) {
return "{}";
}
}
// 新增:获取文件中的所有程序名
static std::vector<std::string> GetProgramNames(LPCTSTR lpszJsonFilePath) {
std::vector<std::string> programs;
try {
std::ifstream ifs(TCHARToString(lpszJsonFilePath));
if (!ifs.is_open()) {
return programs;
}
json root;
ifs >> root;
for (auto it = root.begin(); it != root.end(); ++it) {
programs.push_back(it.key());
}
}
catch (...) {
// 忽略错误,返回空列表
}
return programs;
}
// 新增:获取指定程序中的所有类名
static std::vector<std::string> GetClassNames(LPCTSTR lpszJsonFilePath, LPCTSTR lpszProgramName) {
std::vector<std::string> classes;
try {
std::ifstream ifs(TCHARToString(lpszJsonFilePath));
if (!ifs.is_open()) {
return classes;
}
json root;
ifs >> root;
std::string programName = TCHARToString(lpszProgramName);
if (root.contains(programName)) {
for (auto it = root[programName].begin(); it != root[programName].end(); ++it) {
classes.push_back(it.key());
}
}
}
catch (...) {
// 忽略错误,返回空列表
}
return classes;
}
// 新增:删除指定的程序数据
static BOOL RemoveProgram(LPCTSTR lpszJsonFilePath, LPCTSTR lpszProgramName) {
try {
json root;
std::ifstream ifs(TCHARToString(lpszJsonFilePath));
if (ifs.is_open()) {
ifs >> root;
ifs.close();
}
std::string programName = TCHARToString(lpszProgramName);
if (root.contains(programName)) {
root.erase(programName);
std::ofstream ofs(TCHARToString(lpszJsonFilePath));
if (!ofs.is_open()) {
return FALSE;
}
ofs << root.dump(4);
return TRUE;
}
return FALSE;
}
catch (...) {
return FALSE;
}
}
// 新增:删除指定的类数据
static BOOL RemoveClass(LPCTSTR lpszJsonFilePath, LPCTSTR lpszProgramName, LPCTSTR lpszClassName) {
try {
json root;
std::ifstream ifs(TCHARToString(lpszJsonFilePath));
if (ifs.is_open()) {
ifs >> root;
ifs.close();
}
std::string programName = TCHARToString(lpszProgramName);
std::string className = TCHARToString(lpszClassName);
if (root.contains(programName) && root[programName].contains(className)) {
root[programName].erase(className);
if (root[programName].empty()) {
root.erase(programName);
}
std::ofstream ofs(TCHARToString(lpszJsonFilePath));
if (!ofs.is_open()) {
return FALSE;
}
ofs << root.dump(4);
return TRUE;
}
return FALSE;
}
catch (...) {
return FALSE;
}
}
// 新增:检查指定的类是否存在
static BOOL ClassExists(LPCTSTR lpszJsonFilePath, LPCTSTR lpszProgramName, LPCTSTR lpszClassName) {
try {
std::ifstream ifs(TCHARToString(lpszJsonFilePath));
if (!ifs.is_open()) {
return FALSE;
}
json root;
ifs >> root;
std::string programName = TCHARToString(lpszProgramName);
std::string className = TCHARToString(lpszClassName);
return root.contains(programName) && root[programName].contains(className);
}
catch (...) {
return FALSE;
}
}
private:
// TCHAR 到 string 的转换
static std::string TCHARToString(LPCTSTR str) {
if (str == nullptr) return "";
#ifdef UNICODE
int len = WideCharToMultiByte(CP_UTF8, 0, str, -1, nullptr, 0, nullptr, nullptr);
if (len == 0) return "";
std::string result(len - 1, 0);
WideCharToMultiByte(CP_UTF8, 0, str, -1, &result[0], len, nullptr, nullptr);
return result;
#else
return std::string(str);
#endif
}
// 合并JSON数据的辅助函数
template<typename T>
static void MergeJsonData(json& target, const T& source) {
// 将源对象转换为JSON
json sourceJson = source;
// 如果目标是空对象,直接赋值
if (target.empty() || !target.is_object()) {
target = sourceJson;
return;
}
// 合并对象:对于相同的字段,使用源数据覆盖;对于不同的字段,保留两者
if (sourceJson.is_object() && target.is_object()) {
for (auto it = sourceJson.begin(); it != sourceJson.end(); ++it) {
target[it.key()] = it.value();
}
}
else {
// 如果不是对象,直接覆盖
target = sourceJson;
}
}
};
CDataClassToJson.cpp
c
#include "stdafx.h"
#include "DataClassToJson.h"
#include <fstream>
#include <sstream>
CDataClassToJson::CDataClassToJson()
{
}
CDataClassToJson::~CDataClassToJson()
{
}
BOOL CDataClassToJson::FileExists(LPCTSTR lpszFilePath)
{
CFileStatus status;
return CFile::GetStatus(lpszFilePath, status);
}
CString CDataClassToJson::ReadFileToString(LPCTSTR lpszFilePath)
{
CString strContent;
CStdioFile file;
if (file.Open(lpszFilePath, CFile::modeRead | CFile::typeText)) {
CString strLine;
while (file.ReadString(strLine)) {
strContent += strLine;
}
file.Close();
}
else {
m_strLastError.Format(_T("无法打开文件: %s"), lpszFilePath);
}
return strContent;
}
BOOL CDataClassToJson::WriteStringToFile(LPCTSTR lpszFilePath, LPCTSTR lpszContent)
{
CStdioFile file;
if (file.Open(lpszFilePath, CFile::modeCreate | CFile::modeWrite | CFile::typeText)) {
file.WriteString(lpszContent);
file.Close();
return TRUE;
}
m_strLastError.Format(_T("无法写入文件: %s"), lpszFilePath);
return FALSE;
}
std::string CDataClassToJson::CStringToStdString(LPCTSTR lpszStr)
{
#ifdef _UNICODE
// Unicode 转 ANSI
int nLen = WideCharToMultiByte(CP_UTF8, 0, lpszStr, -1, NULL, 0, NULL, NULL);
if (nLen <= 0) return "";
char* pBuffer = new char[nLen];
WideCharToMultiByte(CP_UTF8, 0, lpszStr, -1, pBuffer, nLen, NULL, NULL);
std::string result(pBuffer);
delete[] pBuffer;
return result;
#else
// ANSI 直接转换
return std::string(lpszStr);
#endif
}
CString CDataClassToJson::StdStringToCString(const std::string& str)
{
#ifdef _UNICODE
// ANSI 转 Unicode
int nLen = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
if (nLen <= 0) return _T("");
wchar_t* pBuffer = new wchar_t[nLen];
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, pBuffer, nLen);
CString result(pBuffer);
delete[] pBuffer;
return result;
#else
// ANSI 直接转换
return CString(str.c_str());
#endif
}
BOOL CDataClassToJson::EnsureJsonFileExists(LPCTSTR lpszJsonFilePath, LPCTSTR lpszProgramName)
{
if (FileExists(lpszJsonFilePath)) {
return TRUE; // 文件已存在
}
// 创建新的JSON文件结构
std::string strProgramName = CStringToStdString(lpszProgramName);
json newJson;
newJson[strProgramName] = json::object(); // 创建空的Program对象
// 写入文件
std::ofstream file(CStringToStdString(lpszJsonFilePath));
if (!file.is_open()) {
m_strLastError.Format(_T("无法创建JSON文件: %s"), lpszJsonFilePath);
return FALSE;
}
file << newJson.dump(4); // 缩进4个空格
file.close();
return TRUE;
}
BOOL CDataClassToJson::UpdateJsonFileWithData(LPCTSTR lpszJsonFilePath,
LPCTSTR lpszProgramName,
LPCTSTR lpszClassName,
const std::map<std::string, std::string>& fieldValues)
{
try {
// 读取现有JSON文件
std::ifstream file(CStringToStdString(lpszJsonFilePath));
if (!file.is_open()) {
m_strLastError.Format(_T("无法打开JSON文件: %s"), lpszJsonFilePath);
return FALSE;
}
json jsonData;
file >> jsonData;
file.close();
std::string strProgramName = CStringToStdString(lpszProgramName);
std::string strClassName = lpszClassName ? CStringToStdString(lpszClassName) : "DataClass";
// 确保Program存在
if (!jsonData.contains(strProgramName)) {
jsonData[strProgramName] = json::object();
}
// 确保Class存在
if (!jsonData[strProgramName].contains(strClassName)) {
jsonData[strProgramName][strClassName] = json::object();
}
// 更新字段值
for (const auto& field : fieldValues) {
jsonData[strProgramName][strClassName][field.first] = field.second;
}
// 写回文件
std::ofstream outFile(CStringToStdString(lpszJsonFilePath));
if (!outFile.is_open()) {
m_strLastError.Format(_T("无法写入JSON文件: %s"), lpszJsonFilePath);
return FALSE;
}
outFile << jsonData.dump(4);
outFile.close();
return TRUE;
}
catch (const std::exception& e) {
m_strLastError = _T("JSON处理错误: ") + CString(e.what());
return FALSE;
}
}
以下为DB数据库新建和添加json文件的接口:
注意需要导入sqlite3数据库
sqlite3详细安装和导入方式可见:点击进入sqlite3数据库安装配置
CDynamicJsonSQLiteDB.h
cpp
#pragma once
#pragma once
#include <vector>
#include <map>
#include <string>
#include "sqlite3.h"
class CDynamicJsonSQLiteDB
{
public:
CDynamicJsonSQLiteDB();
virtual ~CDynamicJsonSQLiteDB();
// 主要接口
BOOL InitializeDBFromJson(LPCTSTR lpszJsonFilePath);
BOOL AddDataRecord(LPCTSTR lpszJsonFilePath); // 修改:传入JSON文件名
BOOL ExportDataToJson(int nRecordNum, LPCTSTR lpszOutputJsonFile);
// 辅助函数
BOOL IsDBOpen() const { return m_pDB != NULL; }
CString GetLastError() const { return m_strLastError; }
void CloseDB();
CString GetDBPath() const { return m_strDBPath; }
// 新增:获取当前记录数量
int GetRecordCount();
private:
BOOL ValidateFilePath(LPCTSTR lpszFilePath);
CString GetValidFileName(LPCTSTR lpszFileName);
private:
sqlite3* m_pDB;
CString m_strDBPath;
CString m_strLastError;
// JSON结构信息
std::vector<CString> m_tableNames; // 主表名(PROGRAM1, PROGRAM2等)
std::map<CString, std::vector<CString>> m_tableFields; // 表字段映射
std::map<CString, std::map<CString, std::vector<CString>>> m_subTableFields; // 子表字段映射
// 内部方法
CString ReadJsonFile(LPCTSTR lpszFilePath);
BOOL WriteJsonFile(LPCTSTR lpszFilePath, LPCTSTR lpszContent);
BOOL ExecuteSQL(LPCTSTR lpszSQL);
BOOL TableExists(LPCTSTR lpszTableName);
// JSON结构分析
BOOL AnalyzeJsonStructure(LPCTSTR lpszJsonData);
BOOL ParseJsonObject(LPCTSTR lpszJsonData, CString strParentKey = _T(""));
void AddFieldToTable(const CString& strParentKey, const CString& strFieldName);
BOOL CreateDatabaseTables();
BOOL ValidateJsonStructure(LPCTSTR lpszJsonData);
// 数据操作
BOOL InsertJsonData(LPCTSTR lpszJsonData, int nRecordNum); // 内部使用,传入JSON数据
BOOL InsertJsonFromFile(LPCTSTR lpszJsonFilePath, int nRecordNum); // 新增:从文件插入
BOOL ParseAndInsertData(LPCTSTR lpszJsonData, CString strParentPath, int nRecordNum);
void ExtractAllFieldsFromJson(LPCTSTR lpszJsonData, std::map<CString, CString>& fieldValues);
// 数据导出
CString GenerateJsonFromData(int nRecordNum);
BOOL BuildJsonForTable(CString& strJson, LPCTSTR lpszTableName, int nRecordNum);
// 字符串处理
CString EscapeSQLString(LPCTSTR lpszInput);
CString GetCurrentTimestamp();
/*void CheckSQLiteTime();*/
CString ExtractJsonValue(LPCTSTR lpszJsonData, LPCTSTR lpszKey);
// 记录管理
int GetNextRecordNum();
// SQLite回调
static int SQLiteCallback(void* data, int argc, char** argv, char** azColName);
};
struct SQueryResult
{
std::vector<std::map<CString, CString>> rows;
};
CDynamicJsonSQLiteDB.cpp
cpp
#include "stdafx.h"
#include "DynamicJsonSQLiteDB.h"
//#include "stdafx.h"
//#include "DynamicJsonSQLiteDB.h"
#include <fstream>
#include <sstream>
// SQLite回调函数
int CDynamicJsonSQLiteDB::SQLiteCallback(void* data, int argc, char** argv, char** azColName)
{
SQueryResult* pResult = static_cast<SQueryResult*>(data);
std::map<CString, CString> row;
for (int i = 0; i < argc; i++) {
CString strColName = CString(azColName[i]);
CString strValue = argv[i] ? CString(argv[i]) : _T("");
row[strColName] = strValue;
}
pResult->rows.push_back(row);
return 0;
}
CDynamicJsonSQLiteDB::CDynamicJsonSQLiteDB() : m_pDB(NULL)
{
}
CDynamicJsonSQLiteDB::~CDynamicJsonSQLiteDB()
{
CloseDB();
}
void CDynamicJsonSQLiteDB::CloseDB()
{
if (m_pDB) {
sqlite3_close(m_pDB);
m_pDB = NULL;
}
}
CString CDynamicJsonSQLiteDB::ReadJsonFile(LPCTSTR lpszFilePath)
{
CString strContent;
CFile file;
// 使用二进制模式读取,避免编码问题
if (file.Open(lpszFilePath, CFile::modeRead | CFile::shareDenyNone)) {
ULONGLONG dwFileLength = file.GetLength();
if (dwFileLength > 0) {
// 读取文件内容
CStringA strContentA;
char* pBuffer = strContentA.GetBuffer((int)dwFileLength + 1);
file.Read(pBuffer, (UINT)dwFileLength);
pBuffer[dwFileLength] = '\0';
strContentA.ReleaseBuffer();
// 转换为Unicode
strContent = CString(strContentA);
}
file.Close();
}
else {
m_strLastError.Format(_T("无法打开文件: %s"), lpszFilePath);
}
return strContent;
}
BOOL CDynamicJsonSQLiteDB::WriteJsonFile(LPCTSTR lpszFilePath, LPCTSTR lpszContent)
{
CFile file;
// 使用二进制模式写入
if (file.Open(lpszFilePath, CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive)) {
// 转换为UTF8写入
CStringA contentA(lpszContent);
file.Write(contentA, contentA.GetLength());
file.Close();
return TRUE;
}
m_strLastError.Format(_T("无法写入文件: %s"), lpszFilePath);
return FALSE;
}
BOOL CDynamicJsonSQLiteDB::ExecuteSQL(LPCTSTR lpszSQL)
{
if (!m_pDB) {
m_strLastError = _T("数据库未打开");
return FALSE;
}
char* errorMsg = nullptr;
// 将Unicode SQL转换为UTF8
CStringA sqlA(lpszSQL);
if (sqlite3_exec(m_pDB, sqlA, nullptr, nullptr, &errorMsg) != SQLITE_OK) {
if (errorMsg) {
// 将错误信息从UTF8转换为Unicode
m_strLastError = CString(errorMsg);
sqlite3_free(errorMsg);
}
else {
m_strLastError = _T("未知SQL错误");
}
return FALSE;
}
return TRUE;
}
BOOL CDynamicJsonSQLiteDB::TableExists(LPCTSTR lpszTableName)
{
CString sql;
sql.Format(_T("SELECT name FROM sqlite_master WHERE type='table' AND name='%s';"), lpszTableName);
SQueryResult result;
char* errorMsg = nullptr;
CStringA sqlA(sql);
if (sqlite3_exec(m_pDB, sqlA, SQLiteCallback, &result, &errorMsg) != SQLITE_OK) {
if (errorMsg) sqlite3_free(errorMsg);
return FALSE;
}
return !result.rows.empty();
}
CString CDynamicJsonSQLiteDB::EscapeSQLString(LPCTSTR lpszInput)
{
/*CString strOutput = lpszInput;
strOutput.Replace(_T("'"), _T("''"));
return strOutput;*/
CString strResult = lpszInput;
// 先清理字符串
//strResult.Trim();
// 首先去除首尾空白
strResult.Trim();
//手动挑选去除一些末尾key值的value不对的情况
strResult.Replace(_T("\r"), _T(""));
strResult.Replace(_T("\n"), _T(""));
strResult.Replace(_T("\""), _T(""));
strResult.Replace(_T("}"), _T(""));
strResult.Replace(_T("{"), _T(""));
// 移除常见的JSON转义字符问题
strResult.Replace(_T("\\\""), _T("\"")); // 转义双引号
strResult.Replace(_T("\\\\"), _T("\\")); // 转义反斜杠
strResult.Replace(_T("\\/"), _T("/")); // 转义斜杠
strResult.Replace(_T("\\b"), _T("")); // 退格符
strResult.Replace(_T("\\f"), _T("")); // 换页符
strResult.Replace(_T("\\n"), _T("")); // 换行符
strResult.Replace(_T("\\r"), _T("")); // 回车符
strResult.Replace(_T("\\t"), _T("")); // 制表符
// 移除控制字符(ASCII < 32)
CString strCleaned;
int nLength = strResult.GetLength();
for (int i = 0; i < nLength; i++) {
TCHAR ch = strResult[i];
if (ch >= 32 || ch == _T('\t') || ch == _T('\n') || ch == _T('\r')) {
strCleaned += ch;
}
}
// 如果字符串被引号包围,去掉它们(但保留转义的内容)
if (strResult.GetLength() >= 2) {
// 检查是否被双引号包围
if (strResult[0] == _T('"') && strResult[strResult.GetLength() - 1] == _T('"')) {
strResult = strResult.Mid(1, strResult.GetLength() - 2);
}
// 检查是否被单引号包围
else if (strResult[0] == _T('\'') && strResult[strResult.GetLength() - 1] == _T('\'')) {
strResult = strResult.Mid(1, strResult.GetLength() - 2);
}
}
// 转义SQL特殊字符
strResult.Replace(_T("'"), _T("''"));
strResult.Replace(_T("\\"), _T("\\\\"));
strResult.Trim();
return strResult;
}
CString CDynamicJsonSQLiteDB::GetCurrentTimestamp()
{
CTime now = CTime::GetCurrentTime();
return now.Format(_T("%Y-%m%d %H:%M:%S"));
}
CString CDynamicJsonSQLiteDB::ExtractJsonValue(LPCTSTR lpszJsonData, LPCTSTR lpszKey)
{
CString strData = lpszJsonData;
CString strSearch;
strSearch.Format(_T("\"%s\":\""), lpszKey);
int nStart = strData.Find(strSearch);
if (nStart == -1) {
// 尝试查找不带引号的值
strSearch.Format(_T("\"%s\":"), lpszKey);
nStart = strData.Find(strSearch);
if (nStart == -1) return _T("");
nStart += strSearch.GetLength();
int nEnd = strData.Find(_T(","), nStart);
if (nEnd == -1) nEnd = strData.Find(_T("}"), nStart);
if (nEnd == -1) return _T("");
CString strValue = strData.Mid(nStart, nEnd - nStart);
strValue.Trim();
// 移除可能的引号
if (strValue.GetLength() >= 2 && strValue[0] == _T('"') && strValue[strValue.GetLength() - 1] == _T('"')) {
strValue = strValue.Mid(1, strValue.GetLength() - 2);
}
return strValue;
}
nStart += strSearch.GetLength();
int nEnd = strData.Find(_T("\""), nStart);
if (nEnd == -1) return _T("");
return strData.Mid(nStart, nEnd - nStart);
}
int CDynamicJsonSQLiteDB::GetNextRecordNum()
{
CString sql = _T("SELECT MAX(record_num) as max_num FROM PROGRAMAll");
SQueryResult result;
char* errorMsg = nullptr;
CStringA sqlA(sql);
int nRecordNum = 1;
if (sqlite3_exec(m_pDB, sqlA, SQLiteCallback, &result, &errorMsg) == SQLITE_OK) {
if (!result.rows.empty()) {
CString strMaxNum = result.rows[0][_T("max_num")];
if (!strMaxNum.IsEmpty()) {
nRecordNum = _ttoi(strMaxNum) + 1;
}
}
}
else {
if (errorMsg) sqlite3_free(errorMsg);
}
return nRecordNum;
}
int CDynamicJsonSQLiteDB::GetRecordCount()
{
CString sql = _T("SELECT COUNT(DISTINCT record_num) as record_count FROM PROGRAMAll");
SQueryResult result;
char* errorMsg = nullptr;
CStringA sqlA(sql);
int nCount = 0;
if (sqlite3_exec(m_pDB, sqlA, SQLiteCallback, &result, &errorMsg) == SQLITE_OK) {
if (!result.rows.empty()) {
CString strCount = result.rows[0][_T("record_count")];
if (!strCount.IsEmpty()) {
nCount = _ttoi(strCount);
}
}
}
else {
if (errorMsg) sqlite3_free(errorMsg);
}
return nCount;
}
BOOL CDynamicJsonSQLiteDB::ValidateFilePath(LPCTSTR lpszFilePath)
{
//if (_tcslen(lpszFilePath) == 0) {
// return FALSE;
//}
//// 检查路径长度
//if (_tcslen(lpszFilePath) > MAX_PATH - 1) {
// return FALSE;
//}
//// 检查非法字符
//CString strInvalidChars = _T("\\/:*?\"<>|");
//CString strPath = lpszFilePath;
//for (int i = 0; i < strInvalidChars.GetLength(); i++) {
// if (strPath.Find(strInvalidChars[i]) != -1) {
// return FALSE;
// }
//}
//return TRUE;
if (_tcslen(lpszFilePath) == 0) {
m_strLastError = _T("文件路径为空");
return FALSE;
}
//// 基本长度检查
//if (_tcslen(lpszFilePath) > MAX_PATH - 1) {
// m_strLastError = _T("文件路径过长");
// return FALSE;
//}
// 检查文件是否存在(对于输入文件)
CFileStatus status;
if (!CFile::GetStatus(lpszFilePath, status)) {
// 对于输出文件,检查目录是否存在
CString strPath = lpszFilePath;
int nLastSlash = strPath.ReverseFind(_T('\\'));
if (nLastSlash != -1) {
CString strDir = strPath.Left(nLastSlash);
DWORD dwAttrib = GetFileAttributes(strDir);
if (dwAttrib == INVALID_FILE_ATTRIBUTES || !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) {
m_strLastError = _T("目录不存在: ") + strDir;
return FALSE;
}
}
}
return TRUE;
}
CString CDynamicJsonSQLiteDB::GetValidFileName(LPCTSTR lpszFileName)
{
CString strValidName = lpszFileName;
// 替换非法字符
strValidName.Replace(_T("\\"), _T("_"));
strValidName.Replace(_T("/"), _T("_"));
strValidName.Replace(_T(":"), _T("_"));
strValidName.Replace(_T("*"), _T("_"));
strValidName.Replace(_T("?"), _T("_"));
strValidName.Replace(_T("\""), _T("_"));
strValidName.Replace(_T("<"), _T("_"));
strValidName.Replace(_T(">"), _T("_"));
strValidName.Replace(_T("|"), _T("_"));
return strValidName;
}
BOOL CDynamicJsonSQLiteDB::InitializeDBFromJson(LPCTSTR lpszJsonFilePath)
{
// 验证输入文件路径
if (!ValidateFilePath(lpszJsonFilePath)) {
m_strLastError = _T("无效的JSON文件路径");
return FALSE;
}
// 检查JSON文件是否存在
CFileStatus status;
if (!CFile::GetStatus(lpszJsonFilePath, status)) {
m_strLastError.Format(_T("JSON文件不存在: %s"), lpszJsonFilePath);
return FALSE;
}
// 读取JSON文件
CString strJsonContent = ReadJsonFile(lpszJsonFilePath);
if (strJsonContent.IsEmpty()) {
return FALSE;
}
// 分析JSON结构
if (!AnalyzeJsonStructure(strJsonContent)) {
return FALSE;
}
// 生成数据库文件路径
CString strJsonFile = lpszJsonFilePath;
CString strDBDirectory;
CString strDBFileName;
// 提取目录
int nLastSlash = strJsonFile.ReverseFind(_T('\\'));
if (nLastSlash != -1) {
strDBDirectory = strJsonFile.Left(nLastSlash + 1);
strDBFileName = strJsonFile.Mid(nLastSlash + 1);
}
else {
strDBDirectory = _T(".\\");
strDBFileName = strJsonFile;
}
// 处理文件名
int nLastDot = strDBFileName.ReverseFind(_T('.'));
if (nLastDot != -1) {
strDBFileName = strDBFileName.Left(nLastDot);
}
// 确保文件名有效
strDBFileName = GetValidFileName(strDBFileName);
if (strDBFileName.IsEmpty()) {
strDBFileName = _T("default_database");
}
// 构建完整数据库路径
m_strDBPath = strDBDirectory + strDBFileName + _T(".db");
// 确保目录存在
CreateDirectory(strDBDirectory, NULL);
// 删除已存在的数据库文件(如果需要重新创建)
// DeleteFile(m_strDBPath);
// 打开数据库
CStringA dbPathA(m_strDBPath);
if (sqlite3_open(dbPathA, &m_pDB) != SQLITE_OK) {
m_strLastError.Format(_T("无法创建数据库文件: %s\nSQLite错误: %s"),
m_strDBPath, CString(sqlite3_errmsg(m_pDB)));
return FALSE;
}
// 设置数据库参数
ExecuteSQL(_T("PRAGMA encoding = 'UTF-8';"));
ExecuteSQL(_T("PRAGMA foreign_keys = ON;"));
ExecuteSQL(_T("PRAGMA journal_mode = WAL;"));
// 创建表结构
if (!CreateDatabaseTables()) {
CloseDB();
return FALSE;
}
// 记录成功信息
CString strSuccessMsg;
strSuccessMsg.Format(_T("数据库初始化成功:\nJSON文件: %s\n数据库文件: %s"),
lpszJsonFilePath, m_strDBPath);
m_strLastError = strSuccessMsg; // 可以改为日志记录
return TRUE;
}
BOOL CDynamicJsonSQLiteDB::AnalyzeJsonStructure(LPCTSTR lpszJsonData)
{
// 清空现有结构
m_tableNames.clear();
m_tableFields.clear();
m_subTableFields.clear();
return ParseJsonObject(lpszJsonData);
}
//BOOL CDynamicJsonSQLiteDB::ParseJsonObject(LPCTSTR lpszJsonData, CString strParentKey)
//{
// CString strData = lpszJsonData;
// strData.Trim();
//
// if (strData.GetLength() < 2 || strData[0] != _T('{') || strData[strData.GetLength() - 1] != _T('}')) {
// m_strLastError = _T("无效的JSON格式");
// return FALSE;
// }
//
// // 移除外层大括号
// CString strContent = strData.Mid(1, strData.GetLength() - 2);
// strContent.Trim();
//
// int nPos = 0;
//
// while (nPos < strContent.GetLength()) {
// // 查找键
// int nKeyStart = strContent.Find(_T('"'), nPos);
// if (nKeyStart == -1) break;
//
// int nKeyEnd = strContent.Find(_T('"'), nKeyStart + 1);
// if (nKeyEnd == -1) break;
//
// CString strKey = strContent.Mid(nKeyStart + 1, nKeyEnd - nKeyStart - 1);
//
// // 查找冒号
// int nColonPos = strContent.Find(_T(':'), nKeyEnd + 1);
// if (nColonPos == -1) break;
//
// // 查找值开始位置
// int nValueStart = nColonPos + 1;
// while (nValueStart < strContent.GetLength() &&
// (strContent[nValueStart] == _T(' ') || strContent[nValueStart] == _T('\t'))) {
// nValueStart++;
// }
//
// if (nValueStart >= strContent.GetLength()) break;
//
// // 判断值类型
// if (strContent[nValueStart] == _T('{')) {
// // 对象类型 - 递归解析
// int nBraceCount = 1;
// int nValueEnd = nValueStart + 1;
//
// while (nValueEnd < strContent.GetLength() && nBraceCount > 0) {
// if (strContent[nValueEnd] == _T('{')) nBraceCount++;
// else if (strContent[nValueEnd] == _T('}')) nBraceCount--;
// nValueEnd++;
// }
//
// if (nBraceCount != 0) break;
//
// CString strSubContent = strContent.Mid(nValueStart, nValueEnd - nValueStart);
//
// if (strParentKey.IsEmpty()) {
// // 顶级表(PROGRAM1, PROGRAM2等)
// m_tableNames.push_back(strKey);
// m_subTableFields[strKey] = std::map<CString, std::vector<CString>>();
// ParseJsonObject(strSubContent, strKey);
// }
// else {
// // 子表(P1Model1, P1Model2等)
// m_subTableFields[strParentKey][strKey] = std::vector<CString>();
// ParseJsonObject(strSubContent, strParentKey + _T(".") + strKey);
// }
//
// nPos = nValueEnd;
// }
// else if (strContent[nValueStart] == _T('"')) {
// // 字符串值 - 字段
// int nValueEnd = strContent.Find(_T('"'), nValueStart + 1);
// if (nValueEnd == -1) break;
//
// if (!strParentKey.IsEmpty()) {
// // 添加到对应的表或子表
// if (strParentKey.Find(_T('.')) == -1) {
// // 主表字段
// m_tableFields[strParentKey].push_back(strKey);
// }
// else {
// // 子表字段
// CString strMainTable = strParentKey.Left(strParentKey.Find(_T('.')));
// CString strSubTable = strParentKey.Mid(strParentKey.Find(_T('.')) + 1);
// m_subTableFields[strMainTable][strSubTable].push_back(strKey);
// }
// }
//
// nPos = nValueEnd + 1;
// }
// else {
// // 其他类型(数字、布尔值等)
// int nValueEnd = strContent.Find(_T(','), nValueStart);
// if (nValueEnd == -1) nValueEnd = strContent.Find(_T('}'), nValueStart );
// if (nValueEnd == -1) break;
//
// if (!strParentKey.IsEmpty()) {
// // 添加到对应的表或子表
// if (strParentKey.Find(_T('.')) == -1) {
// // 主表字段
// m_tableFields[strParentKey].push_back(strKey);
// }
// else {
// // 子表字段
// CString strMainTable = strParentKey.Left(strParentKey.Find(_T('.')));
// CString strSubTable = strParentKey.Mid(strParentKey.Find(_T('.')) + 1);
// m_subTableFields[strMainTable][strSubTable].push_back(strKey);
// }
// }
//
// nPos = nValueEnd;
// }
//
// // 跳过逗号
// if (nPos < strContent.GetLength() && strContent[nPos] == _T(',')) nPos++;
// }
//
// return TRUE;
//}
BOOL CDynamicJsonSQLiteDB::ParseJsonObject(LPCTSTR lpszJsonData, CString strParentKey)
{
CString strData = lpszJsonData;
strData.Trim();
if (strData.GetLength() < 2 || strData[0] != _T('{') || strData[strData.GetLength() - 1] != _T('}')) {
m_strLastError = _T("无效的JSON格式");
return FALSE;
}
// 移除外层大括号
CString strContent = strData.Mid(1, strData.GetLength() - 2);
strContent.Trim();
int nPos = 0;
int nLength = strContent.GetLength();
while (nPos < nLength) {
// 查找键
int nKeyStart = strContent.Find(_T('"'), nPos);
if (nKeyStart == -1) break;
int nKeyEnd = strContent.Find(_T('"'), nKeyStart + 1);
if (nKeyEnd == -1) break;
CString strKey = strContent.Mid(nKeyStart + 1, nKeyEnd - nKeyStart - 1);
// 查找冒号
int nColonPos = strContent.Find(_T(':'), nKeyEnd + 1);
if (nColonPos == -1) break;
// 查找值开始位置
int nValueStart = nColonPos + 1;
while (nValueStart < nLength &&
(strContent[nValueStart] == _T(' ') ||
strContent[nValueStart] == _T('\t') ||
strContent[nValueStart] == _T('\r') ||
strContent[nValueStart] == _T('\n'))) {
nValueStart++;
}
if (nValueStart >= nLength) break;
TCHAR chValueStart = strContent[nValueStart];
// 判断值类型
if (chValueStart == _T('{')) {
// 对象类型 - 递归解析
int nBraceCount = 1;
int nValueEnd = nValueStart + 1;
while (nValueEnd < nLength && nBraceCount > 0) {
if (strContent[nValueEnd] == _T('{')) nBraceCount++;
else if (strContent[nValueEnd] == _T('}')) nBraceCount--;
nValueEnd++;
}
if (nBraceCount != 0) break;
CString strSubContent = strContent.Mid(nValueStart, nValueEnd - nValueStart);
if (strParentKey.IsEmpty()) {
// 顶级表(PROGRAM1, PROGRAM2等)
m_tableNames.push_back(strKey);
m_subTableFields[strKey] = std::map<CString, std::vector<CString>>();
ParseJsonObject(strSubContent, strKey);
}
else {
// 子表(P1Model1, P1Model2等)
m_subTableFields[strParentKey][strKey] = std::vector<CString>();
ParseJsonObject(strSubContent, strParentKey + _T(".") + strKey);
}
nPos = nValueEnd;
}
else if (chValueStart == _T('"')) {
// 字符串值 - 字段
int nValueEnd = strContent.Find(_T('"'), nValueStart + 1);
if (nValueEnd == -1) break;
if (!strParentKey.IsEmpty()) {
AddFieldToTable(strParentKey, strKey);
}
nPos = nValueEnd + 1;
}
else {
// 其他类型(数字、布尔值、null等)
int nValueEnd = nValueStart;
// 遍历直到找到逗号、大括号或行尾
while (nValueEnd < nLength) {
TCHAR ch = strContent[nValueEnd];
if (ch == _T(',') || ch == _T('}') || ch == _T(' ')) {
break;
}
nValueEnd++;
}
// 提取值内容(用于调试)
CString strValue = strContent.Mid(nValueStart, nValueEnd - nValueStart);
strValue.Trim();
if (!strParentKey.IsEmpty()) {
AddFieldToTable(strParentKey, strKey);
}
nPos = nValueEnd;
}
// 跳过逗号和空白
while (nPos < nLength &&
(strContent[nPos] == _T(',') ||
strContent[nPos] == _T(' ') ||
strContent[nPos] == _T('\t') ||
strContent[nPos] == _T('\r') ||
strContent[nPos] == _T('\n'))) {
nPos++;
}
}
return TRUE;
}
// 辅助函数:添加字段到对应的表
void CDynamicJsonSQLiteDB::AddFieldToTable(const CString& strParentKey, const CString& strFieldName)
{
if (strParentKey.Find(_T('.')) == -1) {
// 主表字段
m_tableFields[strParentKey].push_back(strFieldName);
}
else {
// 子表字段
CString strMainTable = strParentKey.Left(strParentKey.Find(_T('.')));
CString strSubTable = strParentKey.Mid(strParentKey.Find(_T('.')) + 1);
m_subTableFields[strMainTable][strSubTable].push_back(strFieldName);
}
}
BOOL CDynamicJsonSQLiteDB::CreateDatabaseTables()
{
// 创建总表PROGRAMAll
CString sql = _T("CREATE TABLE IF NOT EXISTS PROGRAMAll (");
sql += _T("id INTEGER PRIMARY KEY AUTOINCREMENT, ");
sql += _T("record_num INTEGER NOT NULL, ");
sql += _T("table_name TEXT NOT NULL, ");
sql += _T("field_path TEXT NOT NULL, "); // 字段路径:表.子表.字段
sql += _T("field_value TEXT, ");
//sql += _T("created_time TEXT DEFAULT CURRENT_TIMESTAMP");// 时间,这个不准
sql += _T("created_time TEXT DEFAULT (datetime('now', 'localtime'))"); // 使用本地时间
sql += _T(");");
if (!ExecuteSQL(sql)) {
return FALSE;
}
// 为每个主表创建对应的数据库表
for (const auto& tableName : m_tableNames) {
CString sql = _T("CREATE TABLE IF NOT EXISTS ") + tableName + _T(" (");
sql += _T("id INTEGER PRIMARY KEY AUTOINCREMENT, ");
sql += _T("record_num INTEGER NOT NULL, ");
//sql += _T("created_time TEXT DEFAULT CURRENT_TIMESTAMP"); //这个时间不准
sql += _T("created_time TEXT DEFAULT (datetime('now', 'localtime'))"); // 使用本地时间
// 添加所有字段(扁平化结构)
for (const auto& subTablePair : m_subTableFields[tableName]) {
for (const auto& fieldName : subTablePair.second) {
CString strFieldPath = subTablePair.first + _T("_") + fieldName;
sql += _T(", ") + strFieldPath + _T(" TEXT");
}
}
sql += _T(");");
if (!ExecuteSQL(sql)) {
return FALSE;
}
}
return TRUE;
}
// 修改后的AddDataRecord函数 - 传入JSON文件名
BOOL CDynamicJsonSQLiteDB::AddDataRecord(LPCTSTR lpszJsonFilePath)
{
if (!m_pDB) {
m_strLastError = _T("数据库未初始化");
return FALSE;
}
// 获取下一个记录编号
int nRecordNum = GetNextRecordNum();
// 从文件插入数据
return InsertJsonFromFile(lpszJsonFilePath, nRecordNum);
}
// 新增:从JSON文件插入数据
BOOL CDynamicJsonSQLiteDB::InsertJsonFromFile(LPCTSTR lpszJsonFilePath, int nRecordNum)
{
// 读取JSON文件
CString strJsonContent = ReadJsonFile(lpszJsonFilePath);
if (strJsonContent.IsEmpty()) {
m_strLastError.Format(_T("无法读取JSON文件: %s"), lpszJsonFilePath);
return FALSE;
}
// 验证JSON结构是否与初始化时一致
if (!ValidateJsonStructure(strJsonContent)) {
m_strLastError = _T("JSON文件结构与初始化时不一致");
return FALSE;
}
// 插入数据
return InsertJsonData(strJsonContent, nRecordNum);
}
// 新增:验证JSON结构是否一致
BOOL CDynamicJsonSQLiteDB::ValidateJsonStructure(LPCTSTR lpszJsonData)
{
// 临时存储解析出的结构
std::vector<CString> tempTableNames;
std::map<CString, std::map<CString, std::vector<CString>>> tempSubTableFields;
// 解析JSON结构
CString strData = lpszJsonData;
strData.Trim();
if (strData.GetLength() < 2 || strData[0] != _T('{') || strData[strData.GetLength() - 1] != _T('}')) {
return FALSE;
}
// 这里简化验证,实际应该完整解析并比较结构
// 检查是否包含所有必需的表
for (const auto& tableName : m_tableNames) {
CString strSearch;
strSearch.Format(_T("\"%s\":"), tableName);
if (strData.Find(strSearch) == -1) {
return FALSE;
}
}
return TRUE;
}
BOOL CDynamicJsonSQLiteDB::InsertJsonData(LPCTSTR lpszJsonData, int nRecordNum)
{
// 提取所有字段值
std::map<CString, CString> fieldValues;
ExtractAllFieldsFromJson(lpszJsonData, fieldValues);
CString strCurrentTime = GetCurrentTimestamp();
// 为每个主表插入数据
for (const auto& tableName : m_tableNames) {
// 构建INSERT语句
CString sql = _T("INSERT INTO ") + tableName + _T(" (record_num");
CString values = _T(" VALUES (") + CString(std::to_string(nRecordNum).c_str());
// 添加字段值
for (const auto& subTablePair : m_subTableFields[tableName]) {
for (const auto& fieldName : subTablePair.second) {
CString strFieldPath = subTablePair.first + _T("_") + fieldName;
CString strFullPath = tableName + _T(".") + subTablePair.first + _T(".") + fieldName;
sql += _T(", ") + strFieldPath;
if (fieldValues.find(strFullPath) != fieldValues.end()) {
values += _T(", '") + EscapeSQLString(fieldValues[strFullPath]) + _T("'");
// 插入到总表
CString allSql;
//allSql.Format(_T("INSERT INTO PROGRAMAll (record_num, created_time, table_name, field_path, field_value ) VALUES (%d, '%s', '%s', '%s', '%s')"),
// nRecordNum, strCurrentTime, tableName, strFullPath, EscapeSQLString(fieldValues[strFullPath]));
allSql.Format(_T("INSERT INTO PROGRAMAll (record_num, table_name, field_path, field_value ) VALUES (%d, '%s', '%s', '%s')"),
nRecordNum, tableName, strFullPath, EscapeSQLString(fieldValues[strFullPath]));
ExecuteSQL(allSql);
}
else {
values += _T(", NULL");
}
}
}
sql += _T(")");
values += _T(")");
sql += values;
if (!ExecuteSQL(sql)) {
return FALSE;
}
}
return TRUE;
}
//
//BOOL CDynamicJsonSQLiteDB::InsertJsonData(LPCTSTR lpszJsonData, int nRecordNum)
//{
// std::map<CString, CString> fieldValues;
// ExtractAllFieldsFromJson(lpszJsonData, fieldValues);
//
// for (const auto& tableName : m_tableNames) {
// CString sql = _T("INSERT INTO ") + tableName + _T(" (record_num");
// CString values = _T(" VALUES (") + CString(std::to_string(nRecordNum).c_str());
//
// for (const auto& subTablePair : m_subTableFields[tableName]) {
// for (const auto& fieldName : subTablePair.second) {
// CString strFieldPath = subTablePair.first + _T("_") + fieldName;
// CString strFullPath = tableName + _T(".") + subTablePair.first + _T(".") + fieldName;
//
// sql += _T(", ") + strFieldPath;
//
// auto it = fieldValues.find(strFullPath);
// if (it != fieldValues.end()) {
// // 清理字段值
// CString cleanedValue = it->second;
// cleanedValue.Trim();
//
// // 移除可能的尾部垃圾字符
// while (cleanedValue.GetLength() > 0 &&
// (cleanedValue[cleanedValue.GetLength() - 1] == _T('"') ||
// cleanedValue[cleanedValue.GetLength() - 1] == _T('}') ||
// cleanedValue[cleanedValue.GetLength() - 1] == _T(' '))) {
// cleanedValue = cleanedValue.Left(cleanedValue.GetLength() - 1);
// }
//
// CString escapedValue = EscapeSQLString(cleanedValue);
// values += _T(", '") + escapedValue + _T("'");
//
// // 插入到总表
// CString allSql;
// allSql.Format(_T("INSERT INTO PROGRAMAll (record_num, table_name, field_path, field_value) VALUES (%d, '%s', '%s', '%s')"),
// nRecordNum, tableName, strFullPath, escapedValue);
// ExecuteSQL(allSql);
// }
// else {
// values += _T(", NULL");
// }
// }
// }
//
// sql += _T(")");
// values += _T(")");
// sql += values;
//
// if (!ExecuteSQL(sql)) {
// return FALSE;
// }
// }
//
// return TRUE;
//}
void CDynamicJsonSQLiteDB::ExtractAllFieldsFromJson(LPCTSTR lpszJsonData, std::map<CString, CString>& fieldValues)
{
CString strData = lpszJsonData;
// 遍历所有表结构来提取字段值
for (const auto& tableName : m_tableNames) {
for (const auto& subTablePair : m_subTableFields[tableName]) {
for (const auto& fieldName : subTablePair.second) {
CString strFullPath = tableName + _T(".") + subTablePair.first + _T(".") + fieldName;
CString strValue = ExtractJsonValue(lpszJsonData, fieldName);
if (!strValue.IsEmpty()) {
fieldValues[strFullPath] = strValue;
}
}
}
}
}
BOOL CDynamicJsonSQLiteDB::ExportDataToJson(int nRecordNum, LPCTSTR lpszOutputJsonFile)
{
if (!m_pDB) {
m_strLastError = _T("数据库未初始化");
return FALSE;
}
CString strJsonContent = GenerateJsonFromData(nRecordNum);
if (strJsonContent.IsEmpty()) {
return FALSE;
}
return WriteJsonFile(lpszOutputJsonFile, strJsonContent);
}
CString CDynamicJsonSQLiteDB::GenerateJsonFromData(int nRecordNum)
{
CString strJson = _T("{\r\n");
// 为每个表生成JSON结构
for (size_t i = 0; i < m_tableNames.size(); i++) {
if (!BuildJsonForTable(strJson, m_tableNames[i], nRecordNum)) {
return _T("");
}
if (i < m_tableNames.size() - 1) {
strJson += _T(",\r\n\r\n");
}
}
strJson += _T("\r\n}");
return strJson;
}
BOOL CDynamicJsonSQLiteDB::BuildJsonForTable(CString& strJson, LPCTSTR lpszTableName, int nRecordNum)
{
// 查询指定记录的数据
CString sql;
sql.Format(_T("SELECT * FROM %s WHERE record_num = %d"), lpszTableName, nRecordNum);
SQueryResult result;
char* errorMsg = nullptr;
CStringA sqlA(sql);
if (sqlite3_exec(m_pDB, sqlA, SQLiteCallback, &result, &errorMsg) != SQLITE_OK) {
if (errorMsg) {
m_strLastError = CString(errorMsg);
sqlite3_free(errorMsg);
}
return FALSE;
}
if (result.rows.empty()) {
m_strLastError.Format(_T("未找到记录编号 %d 的数据"), nRecordNum);
return FALSE;
}
std::map<CString, CString> rowData = result.rows[0];
// 构建JSON结构
strJson += _T("\t\"") + CString(lpszTableName) + _T("\": {\r\n");
// 添加子表
const auto& subTables = m_subTableFields[lpszTableName];
int subTableCount = 0;
for (const auto& subTablePair : subTables) {
strJson += _T("\t\t\"") + subTablePair.first + _T("\":{\r\n");
// 添加字段
const auto& fields = subTablePair.second;
int fieldCount = 0;
for (const auto& fieldName : fields) {
CString strFieldPath = subTablePair.first + _T("_") + fieldName;
CString strValue = _T("\"\"");
if (rowData.find(strFieldPath) != rowData.end() && !rowData[strFieldPath].IsEmpty()) {
strValue = _T("\"") + rowData[strFieldPath] + _T("\"");
}
strJson += _T("\t\t\t\"") + fieldName + _T("\":") + strValue;
if (++fieldCount < fields.size()) {
strJson += _T(",");
}
strJson += _T("\r\n");
}
strJson += _T("\t\t}");
if (++subTableCount < subTables.size()) {
strJson += _T(",");
}
strJson += _T("\r\n");
}
strJson += _T("\t}");
return TRUE;
}