欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++數(shù)據(jù)序列化方式(自定義結(jié)構(gòu)體的保存和讀取)

 更新時間:2023年08月04日 15:21:07   作者:廬州李大爺  
這篇文章主要介紹了C++數(shù)據(jù)序列化方式(自定義結(jié)構(gòu)體的保存和讀取),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

C++數(shù)據(jù)序列化

碰到一個需求,結(jié)構(gòu)體數(shù)據(jù)需要保存下來,以便下次程序打開后再次加載。結(jié)構(gòu)體存在嵌套。

查找資料,確認(rèn)可以通過文件的讀寫進(jìn)行操作,F(xiàn)ILE,fread和fwrite可以實(shí)現(xiàn),以下是測試代碼(使用模板實(shí)現(xiàn)相關(guān)功能)

核心部分是

template <class T>
void write_dataToFile( T *t, const char *filePath)
template <class T>
void read_dataFromFile(T* t, const char *filePath)

兩個文件,主要是利用了FILE的讀寫操作,注意,此方法可能存在瑕疵,文件的size依賴于平臺,如果在A平臺生成(寫)的文件,在B平臺可能會解析(讀)錯誤。

#include <QApplication>
#include <QtDebug>
#include <stdio.h>
#include <errno.h>
#include <string.h>
enum ENUMT{
    DI = 0,
    DO,
    DP
};
struct Info_C{
    QString name = "1212";
    double age = 12.32323;
};
struct Info{
    QString name = "ddsdsd";
    int age = 0;
    ENUMT enumT = DI;
    Info_C info_c;
};
template <class T>
void write_dataToFile( T *t, const char *filePath)
{
    FILE *fp = nullptr;
    fp = fopen(filePath, "w+");
    if (nullptr == fp)
    {
        printf("open failure ,filePath : %s, errno: %d", filePath, errno);
        qDebug("open failure ,filePath : %s, errno: %d", filePath, errno);
        return;
    }
    fwrite(t, sizeof(T), 1, fp);
    fclose(fp);
}
template <class T>
void read_dataFromFile(T* t, const char *filePath)
{
    FILE *fp = fopen(filePath, "r");
    if (nullptr == fp)
    {
        printf("open failure ,filePath : %s, errno: %d", filePath, errno);
        qDebug("open failure ,filePath : %s, errno: %d", filePath, errno);
        return;
    }
    fread(t, sizeof(T), 1, fp);
    fclose(fp);
}
using namespace hv;
int main(int argc, char *argv[])
{
    //讀寫基本類型
    Info writeInfo;
    writeInfo.name = "baseType";
    writeInfo.age = 18;
    writeInfo.enumT = DO;
    write_dataToFile(&writeInfo,"./info.txt");
    Info readInfo;
    read_dataFromFile(&readInfo,"./info.txt");
    qDebug()<<readInfo.name<<readInfo.age<<readInfo.enumT;
    //讀寫容器,vector
    QVector<QString> vec;
    vec.push_back("vec_base1");
    vec.push_back("vec_base2");
    vec.push_back("vec_base3");
    write_dataToFile(&vec,"./info1.txt");
    QVector<QString> vec11;
    read_dataFromFile(&vec11,"./info1.txt");
    qDebug("read:%d\n", vec11.count());
    if(vec11.count() > 2)
        qDebug()<<vec11.at(2);
    //讀寫容器結(jié)構(gòu)體-包含嵌套
    QVector<Info> vec_stu;
    Info stu;
    stu.name = "vec_stu1";
    stu.age = 18;
    stu.enumT = DO;
    vec_stu.push_back(stu);
    Info stu1;
    stu1.name = "vec_stu2";
    stu1.age = 100;
    stu1.enumT = DI;
    stu1.info_c.age = 43.434;
    stu1.info_c.name = "vec_stu_stu";
    vec_stu.push_back(stu1);
    write_dataToFile(&vec_stu,"./info11.txt");
    QVector<Info> vec_stu11;
    read_dataFromFile(&vec_stu11,"./info11.txt");
    qDebug("read vector stu:%d\n", vec_stu11.count());
    if(vec_stu11.count() > 1){
        qDebug()<<vec_stu11.at(1).name<<vec_stu11.at(1).info_c.age<<vec_stu11.at(1).info_c.name;
    }
    return 0;
}

結(jié)果示意圖,可正常的進(jìn)行讀取。

在這里插入圖片描述

常用的c++序列化方法

1、 什么是序列化?

程序員在編寫應(yīng)用程序的時候往往需要將程序的某些數(shù)據(jù)存儲在內(nèi)存中,然后將其寫入某個文件或是將它傳輸?shù)骄W(wǎng)絡(luò)中的另一臺計算機(jī)上以實(shí)現(xiàn)通訊。這個將 程序數(shù)據(jù)轉(zhuǎn)化成能被存儲并傳輸?shù)母袷降倪^程被稱為“序列化”(Serialization),而它的逆過程則可被稱為“反序列化” (Deserialization)。

簡單來說,序列化就是將對象實(shí)例的狀態(tài)轉(zhuǎn)換為可保持或傳輸?shù)母袷降倪^程。與序列化相對的是反序列化,它根據(jù)流重構(gòu)對象。這兩個過程結(jié)合起來,可以輕 松地存儲和傳輸數(shù)據(jù)。例如,可以序列化一個對象,然后使用 HTTP 通過 Internet 在客戶端和服務(wù)器之間傳輸該對象。

總結(jié):

序列化:將對象變成字節(jié)流的形式傳出去。

反序列化:從字節(jié)流恢復(fù)成原來的對象。

序列化簡化了對象的保存和載入,為對象提供了持久性。但是,序列化本身仍具有一定的局限性。

由于序列化一次從文件中載入所有對象,因此,它不適合于大文件編輯器和數(shù)據(jù)庫。對于數(shù)據(jù)庫和大文件編輯器,它們每次只是從文件中讀入一部分。此時,就不應(yīng)該采用文檔的序列化機(jī)制來直接讀取和保存文件了。

另外,使用外部文件格式(預(yù)先定義的文件格式而不是本應(yīng)用程序定義的文件格式)的程序一般也不使用文檔的序列化。

2、 為什么要序列化?好處在哪里?

簡單來說,對象序列化通常用于兩個目的:

(1) 將對象存儲于硬盤上 ,便于以后反序列化使用

(2)在網(wǎng)絡(luò)上傳送對象的字節(jié)序列

對象序列化的好處在哪里?網(wǎng)絡(luò)傳輸方面的便捷性、靈活性就不說了,這里舉個我們經(jīng)??赡馨l(fā)生的需求:你 有一個數(shù)據(jù)結(jié)構(gòu),里面存儲的數(shù)據(jù)是經(jīng)過很多其它數(shù)據(jù)通過非常復(fù)雜的算法生成的,由于數(shù)據(jù)量很大,算法又復(fù)雜,因此生成該數(shù)據(jù)結(jié)構(gòu)所用數(shù)據(jù)的時間可能要很久 (也許幾個小時,甚至幾天),生成該數(shù)據(jù)結(jié)構(gòu)后又要用作其它的計算,那么你在調(diào)試階段,每次運(yùn)行個程序,就光生成數(shù)據(jù)結(jié)構(gòu)就要花上這么長的時間,無疑代價 是非常大的。

如果你確定生成數(shù)據(jù)結(jié)構(gòu)的算法不會變或不常變,那么就可以通過序列化技術(shù)生成數(shù)據(jù)結(jié)構(gòu)數(shù)據(jù)存儲到磁盤上,下次重新運(yùn)行程序時只需要從磁盤上讀 取該對象數(shù)據(jù)即可,所花費(fèi)時間也就讀一個文件的時間,可想而知是多么的快,節(jié)省了我們的開發(fā)時間。

3、最常用的兩種序列化方案使用心得

3.1、Google Protocol Buffers

protobuf相對而言效率應(yīng)該是最高的,不管是安裝效率還是使用效率,protobuf都很高效,而且protobuf不僅用于C++序列化,還可用于Java和Python的序列化,使用范圍很廣。但在使用過程中要注意兩個問題:

(1)protobuf支持的數(shù)據(jù)類型不是很豐富

protobuf屬于輕量級的,因此不能支持太多的數(shù)據(jù)類型,下面是protobuf支持的基本類型列表,一般都能滿足需求,不過在選擇方案之前,還是先看看是否都能支持,以免前功盡棄。同樣該表也值得收藏,作為我們在定義類型時做參考。

(2)protobuf不支持二維數(shù)組(指針),不支持STL容器序列化

這個缺陷挺大,因?yàn)樯詮?fù)雜點(diǎn)的數(shù)據(jù)結(jié)構(gòu)或類結(jié)構(gòu)里出現(xiàn)二維數(shù)組、二維指針和STL容器(set、list、map等)很頻繁,但因?yàn)?protobuf簡單的實(shí)現(xiàn)機(jī)制,只支持一維數(shù)組和指針(用repeated修飾符修飾),不能使用repeated repeated來支持二維數(shù)組, 也不支持STL,因此在選擇該方案之前,一定 要確保你的數(shù)據(jù)結(jié)構(gòu)里沒有這些不支持的類型。

(3)protobuf嵌套后會改變類名稱

protobuf支持類的嵌套,即在一個自定義類型中可以定義另一個自定義類型,但注意嵌套的自定義類型在經(jīng)過protobuf處理后生成的類名稱并不是你定義的類名稱,而是加上了外層的類名稱作為前綴,下面舉一個簡單的例子:

message DFA { ?
? ? ? ? required int32 _size = 1; ?
? ? ? ? message accept_pair { ?
? ? ? ? ? required bool is_accept_state = 1; ?
? ? ? ? ? required bool is_strict_end = 2; ?
? ? ? ? ? optional string app_name = 3; ?
? ? ? ? } ?
? ? ? ? repeated accept_pair accept_states = 2; ?
? ? }

那么嵌套中的accept_pair 生成后的類不是accept_pair 而是DFA_accept_pair 。如果不想改類名稱,將accept_pair 拿到外面與DFA平行定義即可。

3.2 Boost.Serialization

Boost庫是個很龐大的庫,功能非常豐富,序列化只是其中的一個小分支,但為了使用Boost的序列化方案,你需要安裝整個Boost庫,所花費(fèi)的磁盤空間和時間都很多,同樣支持的序列化功能也很強(qiáng)大,既支持二維數(shù)組(指針),也支持STL容器,更不需要我們用某種特殊的格式重新定義我們的類結(jié)構(gòu),其非侵入的性質(zhì)使得我們無須改動已有的類結(jié)構(gòu)即可序列化,這時非常贊的一個性質(zhì)。但是由于體積龐大,安裝復(fù)雜,如果只是簡單的序列化,沒必要使用該方案,只有protobuf不能滿足你的需求時,才應(yīng)該考慮該方案。

  • text_oarchive:文本序列化
  • binary_oarchive:二進(jìn)制系列化

例子:

#include <iostream>
#include <boost\archive\text_oarchive.hpp>
#include <boost\archive\text_iarchive.hpp>
//#include <boost\archive\binary_oarchive.hpp>
//#include <boost\archive\binary_iarchive.hpp>
#include <string>
#include <fstream>
void Save()
{
?? ?/*打開Test.bin 此種方法是利用構(gòu)造函數(shù)打開*/
?? ?std::ofstream file("Test.bin");
?? ?/*定義oa為二進(jìn)制存儲類型*/
?? ?boost::archive::text_oarchive oa(file);
?? ?//boost::archive::binary_oarchive oa(file);
?? ?int nNum = 0;
?? ?std::cout << "輸入int型" << std::endl;
?? ?std::cin >> nNum;
?? ?float fFloat = 0.0f;
?? ?std::cout << "輸入float型" << std::endl;
?? ?std::cin >> fFloat;
?? ?oa << nNum << fFloat;
?? ?file.close();
}
void Load()
{
?? ?std::ifstream file("Test.bin");
?? ?/*定義ia為二進(jìn)制讀取類型*/
?? ?boost::archive::text_iarchive ia(file);
?? ?//boost::archive::binary_iarchive ia(file);
?? ?/*讀取順序應(yīng)和存儲順序相同 類型也需要相同*/
?? ?int n = 0;
?? ?float f = 0.0f;
?? ?ia >> n >> f;
?? ?std::cout << n << " " << f << std::endl;
?? ?file.close();
}
int main()
{
?? ?int nTemp = 0;
?? ?std::cout << "1.輸入并存儲 ?2.讀取并顯示" << std::endl;
?? ?std::cin >> nTemp;
?? ?switch (nTemp)
?? ?{
?? ?case 1:
?? ??? ?Save();
?? ??? ?break;
?? ?case 2:
?? ??? ?Load();
?? ??? ?break;
?? ?default:
?? ??? ?break;
?? ?}
?? ?while (1);
?? ?return 0;
}

總結(jié)

以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • C++實(shí)現(xiàn)LeetCode(29.兩數(shù)相除)

    C++實(shí)現(xiàn)LeetCode(29.兩數(shù)相除)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(29.兩數(shù)相除),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C 語言基礎(chǔ)教程(我的C之旅開始了)[八]

    C 語言基礎(chǔ)教程(我的C之旅開始了)[八]

    C 語言基礎(chǔ)教程(我的C之旅開始了)[八]...
    2007-02-02
  • C++圖文并茂講解繼承

    C++圖文并茂講解繼承

    繼承是C++面向?qū)ο缶幊讨械囊婚T。繼承是子類繼承父類的特征和行為,或者是繼承父類得方法,使的子類具有父類得的特性和行為。重寫是子類對父類的允許訪問的方法實(shí)行的過程進(jìn)行重新編寫,返回值和形參都不能改變。就是對原本的父類進(jìn)行重新編寫,但是外部接口不能被重寫
    2022-05-05
  • C++多態(tài)的示例詳解

    C++多態(tài)的示例詳解

    多態(tài)按字面的意思就是多種形態(tài)。當(dāng)類之間存在層次結(jié)構(gòu),并且類之間是通過繼承關(guān)聯(lián)時,就會用到多態(tài)。本文將通過三個小案例讓大家更深入的了解一下C++的多態(tài),感興趣的可以了解一下
    2022-06-06
  • C++實(shí)現(xiàn)快捷店會員管理系統(tǒng)

    C++實(shí)現(xiàn)快捷店會員管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)快捷店會員管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • C語言實(shí)現(xiàn)單鏈表反轉(zhuǎn)

    C語言實(shí)現(xiàn)單鏈表反轉(zhuǎn)

    這篇文章主要介紹了C語言實(shí)現(xiàn)單鏈表反轉(zhuǎn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • C語言實(shí)現(xiàn)掃雷游戲小項(xiàng)目

    C語言實(shí)現(xiàn)掃雷游戲小項(xiàng)目

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)掃雷游戲小項(xiàng)目,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • C++ ofstream和ifstream詳細(xì)用法

    C++ ofstream和ifstream詳細(xì)用法

    ofstream是從內(nèi)存到硬盤,ifstream是從硬盤到內(nèi)存,其實(shí)所謂的流緩沖就是內(nèi)存空間,本文小編就為大家詳細(xì)介紹C++ ofstream和ifstream用法,需要的朋友可以參考下面文章的具體內(nèi)容
    2021-09-09
  • win32 api實(shí)現(xiàn)2048游戲示例

    win32 api實(shí)現(xiàn)2048游戲示例

    這篇文章主要介紹了win32 api實(shí)現(xiàn)2048游戲示例,需要的朋友可以參考下
    2014-05-05
  • 解析四則表達(dá)式的編譯過程及生成匯編代碼

    解析四則表達(dá)式的編譯過程及生成匯編代碼

    本篇文章是對四則表達(dá)式的編譯過程及生成匯編代碼進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-06-06

最新評論