C语言,用json文件存储tree

C语言,用json文件存储tree:

1.读取和保存都用递归算法遍历,可以保存任意树结构,相比用INI文件,一致性更好,当然用数据库功能更多更好
2.json数据全部用节点最方便,缺点存储的json文件末端有一个空的{},不太美观
3.json文件读入时最好判断编码,尤其是对手工编辑的文件
4.json的root节点没必要创建在树上,除非要展现多个json文件在同一树上


5.测试程序用VS2010的MFC模板,加入CJSON文件,主要程序段如下:

 

//保存树到json中

cJSON * CFileView::AddJsonNode(HTREEITEM hItem, cJSON *NodePrev)
{
    char text[256]; //no need
    CString str = m_wndFileView.GetItemText(hItem);
    HWND hWndTree = m_wndFileView.m_hWnd;  //no need
    HTREEITEM hChild = TreeView_GetChild(hWndTree, hItem); //no need
    char *p = WcharToChar(str.GetBuffer(0), CP_UTF8);
    cJSON *node;
    //if(hChild != NULL)
    {
        node = cJSON_CreateObject();
        cJSON_AddItemToObject(NodePrev, p, node);
        delete p;
        return node;
    }
    /*else //没必要,反正要有个多余的,用{}也可以,所以都用Obj
    {
        cJSON_AddStringToObject(NodePrev, p, " ");
        delete p;
        return NodePrev;
    }*/
    PRINT(_T("\r\n %s"), str.GetBuffer(0)); //no need
}

void CFileView::RecursionTreeSave(HTREEITEM hItem, cJSON *NodePrev)
{
    if (!hItem)    return;
    HWND hWndTree = m_wndFileView.m_hWnd;
    cJSON *node = AddJsonNode(hItem, NodePrev); //递归函数中增加节点必须在子节点前
    HTREEITEM hChild = TreeView_GetChild(hWndTree, hItem);

    RecursionTreeSave(hChild, node);  //进入子节点
       
    HTREEITEM hSibling =  TreeView_GetNextSibling(hWndTree, hItem);   
    RecursionTreeSave(hSibling, NodePrev);
    //DeleteNode(hItem);  //递归函数中删除只能处理当前节点,放在子节点处理后再处理当前节点 

    return;
}

//======
。。。。。。。
//下面是把树保存为json文件
    HTREEITEM hRoot = m_wndFileView.GetRootItem();
    CFileJson fjson(NULL);
    if(fjson.root != 0) cJSON_Delete(fjson.root);
    fjson.root = 0;
    // 创建 JSON root
    fjson.root = cJSON_CreateObject();
    RecursionTreeSave(hRoot, fjson.root);
    fjson.Save("r:\\tree.json");

 

//======================
//从json读取数据生成树
HTREEITEM CFileView::AddTreeNode(cJSON *jNode, HTREEITEM hParen, HTREEITEM hAfter) { cJSON * node = jNode; if(node == NULL) return NULL; wchar_t *p = CharToWchar(node->string, CP_UTF8); HTREEITEM hItem; if(node->child) { hItem = m_wndFileView.InsertItem(p, 0, 0, hParen, hAfter); delete p; } else { hItem = m_wndFileView.InsertItem(p, 1, 1, hParen, hAfter); delete p; } return hItem; } void CFileView::RecursionTreeLoad(cJSON *jNode, HTREEITEM hParen, HTREEITEM hAfter) { cJSON * node = jNode; if(node == NULL) return; HWND hWndTree = m_wndFileView.m_hWnd; HTREEITEM hItem = AddTreeNode(jNode, hParen, hAfter); //递归函数中增加节点必须在子节点前 cJSON* jNodeChild = node->child; RecursionTreeLoad(jNodeChild, hItem, NULL); //进入child节点 cJSON* jNodeNext = node->next; RecursionTreeLoad(jNodeNext, hParen, hItem); //进入Next节点 return; }

//===================

// 下面是从json文件读取数据,用来生成树,root节点不显示,从root的子节点开始

。。。。。
CFileJson fjson("r:\\tree1.json"); if(fjson.root == 0) { PRINT(_T("\r\n Open fail!")); return; } m_wndFileView.DeleteAllItems(); cJSON *node = fjson.root->child; //XGZ:ROOT NOT FOR TREE NODE RecursionTreeLoad(node, NULL, NULL); HTREEITEM hRoot = m_wndFileView.GetRootItem(); m_wndFileView.Expand(hRoot, TVE_EXPAND);

//===Json的c++封装,只是为了可靠释放

class CFileJson 
{
public:
    CFileJson(const char* filepathname);
    ~CFileJson();
    cJSON * root;
int Save(const char* filepathname);

};

//另外要注意文件打开时判断编码,保存时默认字符串生成UTF-8,

//若只是自己的程序存取自己的文件,这些判断转换都不用,只要打开文件直接读取就行了

CFileJson::CFileJson(const char* filepathname)
{
    root = 0;
    if(filepathname == NULL) return;
    wchar_t* pwText;
    int length;
        
    FILE* fp = fopen(filepathname, "rb");
    if (fp)
    {
        fseek(fp, 0, SEEK_END);  //到文件末尾,0 succes
        int FileLen = ftell(fp);  //到末尾后的位置就是文件长度
        char* p1;
        wchar_t* p2;
        p1 = new char[FileLen + 16];
        fseek(fp, 0, SEEK_SET);  //回到0位置, 0 succes
        length = fread(p1, 1, FileLen + 16, fp);
        fclose(fp);
        *(p1 + length) = 0;
        *(p1 + length + 1) = 0;
        *(p1 + length + 2) = 0;
        *(p1 + length + 3) = 0;

        if (((unsigned char)*p1 == 0xff)
            && ((unsigned char)*(p1 + 1) == 0xfe))  //UTF-16LE
        {
            for (int i = 0; i < length; i += 2)
            {
                *(p1 + i) = *(p1 + i + 2);
                *(p1 + i + 1) = *(p1 + i + 3);
            }
            pwText = (wchar_t*)(p1);
        }
        else if (((unsigned char)*p1 == 0xfe)
            && ((unsigned char)*(p1 + 1) == 0xff))  //UTF-16BE
        {
            for (int i = 0; i < length; i += 2)
            {
                *(p1 + i) = *(p1 + i + 3);
                *(p1 + i + 1) = *(p1 + i + 2);
            } 
            pwText = (wchar_t*)(p1);
        }
        else if (((unsigned char)*p1 == 0xef)
            && ((unsigned char)*(p1 + 1) == 0xbb)
            && ((unsigned char)*(p1 + 2) == 0xbf))//UTF-8 BOM
        {
            p2 = CharToWchar(p1 + 3, CP_UTF8);  //程序统一转换为UTF16LE,这里其实是不需要的,
            delete p1;             
            pwText = (wchar_t*)p2; //UTF-8 BOM 可以和下面UTF-8 一样,偏移3字节,直接解析
        }
        else  //ANSI, UTF-8
        {
            int checknum = FileLen;  //1000000;  //XGZ:NEED CHECK 
            if (checknum > length) checknum = length;

            if (IsUTF8Text(p1, checknum))  //UTF-8
            {
                root = cJSON_Parse(p1);
                delete p1;
                return; 

                //XGZ: THIS APP, CP_UTF8 NO NEED CHANGE TO UTF16LE
                //p2 = CharToWchar(p1, CP_UTF8);
                //delete p1;
                //pwText = (wchar_t*)p2;
            }
            else  //ASCII CP_ACP
            {
                p2 = CharToWchar(p1, CP_ACP);
                delete p1;
                pwText = (wchar_t*)p2;
            }
        }

    char * pdata = WcharToChar(pwText, CP_UTF8);
    root = cJSON_Parse(pdata);  //XGZ:DEFAULT CODE CP_UTF8
    delete pdata;
    }

    return;
}
CFileJson::~CFileJson()
{
    if(root != 0)
    {
        cJSON_Delete(root);
        root = 0;
    }
    return;
}

int CFileJson::Save(const char* filepathname)
{
    FILE *fp = fopen(filepathname,"wb");
    if(root != 0)
    {
        char *pdata = cJSON_Print(root); //XGZ:DEFAULT CODE CP_UTF8
        if(pdata != NULL)
        {
            fwrite(pdata,sizeof(char), strlen(pdata), fp);
        }
        free(pdata);  //cJSON use malloc  //static void *(*cJSON_malloc)(size_t sz) = malloc;
    }

    fclose(fp);
    
    return 0;
}

 

 

 

程序读取json文件后显示在tree上

image

 

json文件: 

image

 

posted @ 2025-12-07 15:07  XGZ21  阅读(4)  评论(0)    收藏  举报