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

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

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

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

應(yīng)用場(chǎng)景

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

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

示例代碼

io.hpp ,對(duì)std::ifstream 以及std::ofstream 的封裝,提供從vector序列化到二進(jìn)制文件和從二進(jìn)制文件反序列化到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ù)寫(xiě)入二進(jìn)制文件,并從二進(jìn)制文件中反序列化到一個(gè)新的vector。

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

注意

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

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

對(duì)于is_trivially_copyable 類(lèi)型對(duì)象的性質(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

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

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

  • 序列化:

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

  • 反序列化:

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

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

為什么需要序列化?

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

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

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

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

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

最后附一個(gè)C/C++序列化庫(kù),boost serialization。

總結(jié)

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

相關(guān)文章

  • C++實(shí)現(xiàn)獲取時(shí)間戳和計(jì)算運(yùn)行時(shí)長(zhǎng)

    C++實(shí)現(xiàn)獲取時(shí)間戳和計(jì)算運(yùn)行時(shí)長(zhǎng)

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

    淺析C++中前置聲明的應(yīng)用與陷阱

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

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

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

    C++?Boost?Foreach超詳細(xì)分析講解

    Boost是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱(chēng)。Boost庫(kù)是一個(gè)可移植、提供源代碼的C++庫(kù),作為標(biāo)準(zhǔn)庫(kù)的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開(kāi)發(fā)引擎之一,是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱(chēng)
    2022-11-11
  • C++ 類(lèi)的靜態(tài)成員深入解析

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

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

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

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

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

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

    C語(yǔ)言小程序 楊輝三角示例代碼

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

    一元多項(xiàng)式加法運(yùn)算

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

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

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

最新評(píng)論