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

C++內(nèi)存數(shù)據(jù)結(jié)構(gòu)與二進制文件之間的序列化和反序列化方式

 更新時間:2023年08月07日 09:26:00   作者:carbon06  
這篇文章主要介紹了C++內(nèi)存數(shù)據(jù)結(jié)構(gòu)與二進制文件之間的序列化和反序列化方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

C++內(nèi)存數(shù)據(jù)結(jié)構(gòu)與二進制文件之間的序列化和反序列化

應用場景

許多后端檢索server啟動時候需要從文件加載到內(nèi)存中構(gòu)建索引,這個過程往往會消耗比較多的時間,這樣會造成sever啟動消耗比較多的時間,在存在多臺服務器的時候會更加明顯。

我們可以將夠構(gòu)建索引的過程獨立成一個單獨的進程,此進程實現(xiàn)的功能是根據(jù)原始文件構(gòu)建索引結(jié)構(gòu),并將索引結(jié)構(gòu)序列化到本地二進制文件,Server在啟動的時候只需要讀取二進制文件就可以構(gòu)造出索引結(jié)構(gòu),可以大大提高啟動速度。

示例代碼

io.hpp ,對std::ifstream 以及std::ofstream 的封裝,提供從vector序列化到二進制文件和從二進制文件反序列化到vector等接口

#ifndef IO_HPP
#define IO_HPP
#include <string>
#include <vector>
#include <fstream>
class FileReader
{
public:
    FileReader(const std::string& filename)
        : input_stream(filename,std::ios::binary)
    {
    }
    /* Read count objects of type T into pointer dest */
    template <typename T> void ReadInto(T *dest, const std::size_t count)
    {
        static_assert(std::is_trivially_copyable<T>::value,
                      "bytewise reading requires trivially copyable type");
        if (count == 0)
            return;
        const auto &result = input_stream.read(reinterpret_cast<char *>(dest), count * sizeof(T));
        const std::size_t bytes_read = input_stream.gcount();
        if (bytes_read != count * sizeof(T) && !result)
        {
            return;
        }
    }
    template <typename T> void ReadInto(std::vector<T> &target)
    {
        ReadInto(target.data(), target.size());
    }
    template <typename T> void ReadInto(T &target) 
    {
         ReadInto(&target, 1); 
    }
    template <typename T> T ReadOne()
    {
        T tmp;
        ReadInto(tmp);
        return tmp;
    }
    std::uint32_t ReadElementCount32() 
    { 
        return ReadOne<std::uint32_t>(); 
    }
    std::uint64_t ReadElementCount64() 
    { 
        return ReadOne<std::uint64_t>(); 
    }
    template <typename T> void DeserializeVector(std::vector<T> &data)
    {
        const auto count = ReadElementCount64();
        data.resize(count);
        ReadInto(data.data(), count);
    }
private:
    std::ifstream input_stream;
};
class FileWriter
{
public:
    FileWriter(const std::string& filename)
        : output_stream(filename,std::ios::binary)
    {
    }
    /* Write count objects of type T from pointer src to output stream */
    template <typename T> void WriteFrom(const T *src, const std::size_t count)
    {
        static_assert(std::is_trivially_copyable<T>::value,
                      "bytewise writing requires trivially copyable type");
        if (count == 0)
            return;
        const auto &result =
            output_stream.write(reinterpret_cast<const char *>(src), count * sizeof(T));
    }
    template <typename T> void WriteFrom(const T &target) 
    { 
        WriteFrom(&target, 1); 
    }
    template <typename T> void WriteOne(const T tmp) 
    { 
        WriteFrom(tmp); 
    }
    void WriteElementCount32(const std::uint32_t count) 
    { 
        WriteOne<std::uint32_t>(count); 
    }
    void WriteElementCount64(const std::uint64_t count) 
    { 
        WriteOne<std::uint64_t>(count); 
    }
    template <typename T> void SerializeVector(const std::vector<T> &data)
    {
        const auto count = data.size();
        WriteElementCount64(count);
        return WriteFrom(data.data(), count);
    }
private:
    std::ofstream output_stream;
};
#endif

binary_io.cpp

#include "io.hpp"
#include <iostream>
struct Data
{
    int a;
    double b;
    friend std::ostream& operator<<(std::ostream& out,const Data& data)
    {
        out << data.a << "," << data.b;
        return out;
    }
};
template<typename T>
void printData(const std::vector<T>& data_vec)
{
    for (const auto data : data_vec)
    {
        std::cout << "{" << data << "} ";
    }
    std::cout << std::endl;
}
template<typename T>
void serializeVector(const std::string& filename,const std::vector<T>& data_vec)
{
    FileWriter file_writer(filename);
    file_writer.SerializeVector<T>(data_vec);
}
template<typename T>
void deserializeVector(const std::string& filename,std::vector<T>& data_vec)
{
    FileReader file_reader(filename);
    file_reader.DeserializeVector<T>(data_vec);
}
int main()
{
    std::vector<Data> vec1 = {{1,1.1},{2,2.2},{3,3.3},{4,4.4}};
    std::cout << "before write to binary file.\n";
    printData(vec1);
    const std::string filename = "vector_data";
    std::cout << "serialize vector to binary file.\n";
    serializeVector<Data>(filename,vec1);
    std::vector<Data> vec2;
    deserializeVector<Data>(filename,vec2);
    std::cout << "vector read from binary file.\n";
    printData(vec2);
    return 0;
}

編譯代碼

g++ -std=c++11 binary_io.cpp -o binary_io

執(zhí)行程序

./binary_io

執(zhí)行結(jié)果

執(zhí)行結(jié)果

程序?qū)?nèi)存中vector 數(shù)據(jù)寫入二進制文件,并從二進制文件中反序列化到一個新的vector。

可以看到序列化前和序列化后的結(jié)果一致。

注意

序列化到文件的數(shù)據(jù)結(jié)構(gòu)需要滿足 is_trivially_copyable。std::is_trivially_copyable 在c++11 引入,TriviallyCopyable類型對象有以下性質(zhì)

  • 每個拷貝構(gòu)造函數(shù)是trivial 或者是deleted
  • 每個移動構(gòu)造函數(shù)是trivial 或者是deleted
  • 每個拷貝賦值運算符是trivial 或者是deleted
  • 每個移動賦值運算符是trivial 或者是deleted
  • 以上至少有一個是non-deleted
  • 析構(gòu)函數(shù)是trivial 并且non-deleted

對于is_trivially_copyable 類型對象的性質(zhì),解釋如下

Objects of trivially-copyable types are the only C++ objects that may be safely copied with std::memcpy or serialized to/from binary files with std::ofstream::write()/std::ifstream::read(). In general, a trivially copyable type is any type for which the underlying bytes can be copied to an array of char or unsigned char and into a new object of the same type, and the resulting object would have the same value as the original

只有滿足trivially-copyable的對象才可以保證序列化到二進制文件后, 從二進制文件反序列化到內(nèi)存后的值保持不變。

序列化與反序列化(其實就是一種將各種數(shù)據(jù)轉(zhuǎn)換成二進制流與二進制流的讀取的概念)

  • 序列化:

將數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換稱為二進制數(shù)據(jù)流或者文本流的過程。序列化后的數(shù)據(jù)方便在網(wǎng)絡上傳輸和在硬盤上存儲。

  • 反序列化:

與序列化相反,是將二進制數(shù)據(jù)流或者文本流轉(zhuǎn)換稱為易于處理和閱讀的數(shù)據(jù)結(jié)構(gòu)的過程。

本質(zhì)其實還是一種協(xié)議,一種數(shù)據(jù)格式,方便數(shù)據(jù)的存儲和傳輸。

為什么需要序列化?

我們知道,計算機世界往往是根據(jù)二進制來區(qū)分數(shù)據(jù)的,例如一個字節(jié)、兩個字節(jié)、三個字節(jié)等等,但是,由于在內(nèi)存中或者磁盤上,或者平臺的環(huán)境不同,為了方便數(shù)據(jù)在不同的地方能夠具有相同的含義,我們需要將數(shù)據(jù)轉(zhuǎn)換為一種大家都能識別的格式,二進制或者編碼格式是大家都認同的方式,而序列化正好是將一種數(shù)據(jù)格式轉(zhuǎn)換為二進制數(shù)據(jù)流的過程或者方法,那么該數(shù)據(jù)結(jié)構(gòu)就能夠在任何地方保持其原有的含義,這就是序列化的意義。

什么是編碼?與序列化的區(qū)別?

編碼也是一種約定數(shù)據(jù)的含義的方式。與序列化不同,其約定的是更底層一些的數(shù)據(jù)含義,例如字符的表示,有ASCII、UTF-8、GBK等等,例如整數(shù)的表示,1=00000001一個字節(jié),編碼約定了數(shù)據(jù)格式的最小單元,序列化是依賴于字符編碼之上的一種數(shù)據(jù)格式。

二進制流和文本流的區(qū)別:

二進制流是以二進制為最小單位進行編碼,例如多少個bit代表什么,文本流是以字符來進行編碼,約定好多少個字節(jié)(通常是以字節(jié)為單位)代表什么。

最后附一個C/C++序列化庫,boost serialization。

總結(jié)

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

相關文章

  • C++實現(xiàn)獲取時間戳和計算運行時長

    C++實現(xiàn)獲取時間戳和計算運行時長

    這篇文章主要為大家詳細介紹了如何使用C++實現(xiàn)獲取時間戳和計算運行時長功能,文中的示例代碼講解詳細,有需要的小伙伴可以參考一下
    2024-12-12
  • 淺析C++中前置聲明的應用與陷阱

    淺析C++中前置聲明的應用與陷阱

    以下是對C++中前置聲明的應用與陷阱進行了詳細的分析介紹,需要的朋友參考下
    2013-07-07
  • C++中虛表是什么意思(概念及示例)

    C++中虛表是什么意思(概念及示例)

    虛函數(shù)表,以及虛函數(shù)指針是實現(xiàn)多態(tài)性(Polymorphism)的關鍵機制,這篇文章主要介紹了C++中虛表是什么意思(概念及示例),需要的朋友可以參考下
    2024-03-03
  • C++?Boost?Foreach超詳細分析講解

    C++?Boost?Foreach超詳細分析講解

    Boost是為C++語言標準庫提供擴展的一些C++程序庫的總稱。Boost庫是一個可移植、提供源代碼的C++庫,作為標準庫的后備,是C++標準化進程的開發(fā)引擎之一,是為C++語言標準庫提供擴展的一些C++程序庫的總稱
    2022-11-11
  • C++ 類的靜態(tài)成員深入解析

    C++ 類的靜態(tài)成員深入解析

    在C++中類的靜態(tài)成員變量和靜態(tài)成員函數(shù)是個容易出錯的地方,本文先通過幾個例子來總結(jié)靜態(tài)成員變量和成員函數(shù)使用規(guī)則,再給出一個實例來加深印象
    2013-09-09
  • C++實現(xiàn)拼圖游戲代碼(graphics圖形庫)

    C++實現(xiàn)拼圖游戲代碼(graphics圖形庫)

    這篇文章主要為大家詳細介紹了C++實現(xiàn)拼圖游戲代碼,帶有g(shù)raphics圖形庫,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • 基于QT的TCP通信服務的實現(xiàn)

    基于QT的TCP通信服務的實現(xiàn)

    在項目開發(fā)過程中,很多地方都會用到TCP通信,本文主要介紹了基于QT的TCP通信服務的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-05-05
  • C語言小程序 楊輝三角示例代碼

    C語言小程序 楊輝三角示例代碼

    輸入要顯示的楊輝三角的行數(shù),會打印出金字塔型的楊輝三角,不過行數(shù)太多的話,效果不太好,可以再調(diào)整一下格式控制
    2013-07-07
  • 一元多項式加法運算

    一元多項式加法運算

    今天小編就為大家分享一篇關于一元多項式加法運算,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • C語言實現(xiàn)大數(shù)值金額大寫轉(zhuǎn)換的方法詳解

    C語言實現(xiàn)大數(shù)值金額大寫轉(zhuǎn)換的方法詳解

    這篇文章主要為大家詳細介紹了如何利用C語言實現(xiàn)大數(shù)值金額大寫轉(zhuǎn)換的功能,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-03-03

最新評論