首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ 數據持久化方案:無數據庫場景下的文件存儲與 JSON 實戰

     編輯:關於C++

前言:初學者也能實現數據落地

數據持久化是程序的核心能力。對於未接觸數據庫的開發者,文件 I/O 是最直接的入門路徑。本文從 C++ 文件流基礎出發,對比文本/二進制模式,演示手工解析的局限,最後引入 nlohmann/json 庫實現結構化存儲,兼顧簡潔與擴展性。


一、 C++ 文件流(fstream)核心知識

三大流類別

  • std::ifstream:輸入(讀)
  • std::ofstream:輸出(寫)
  • std::fstream:雙向

均定義於 <fstream>,繼承自 iostream 體系,支持 << >> get() getline() read() write() 等操作。

打開模式標誌(可組合)

標誌含義
ios::in讀模式打開
ios::out寫模式打開(默認截斷文件)
ios::app追加模式(寫入定位到末尾)
ios::ate打開後定位到末尾(可隨後移動)
ios::binary二進制模式(無換行符轉換)
ios::trunc截斷現有文件(out 默認帶此標誌)

std::fstream file("data.bin", std::ios::in | std::ios::out | std::ios::binary);
if (!file.is_open()) { /* 錯誤處理 */ }

文本 vs 二進制

  • 文本模式:int 20000 輸出為 5 字節 "20000",Windows 下 \n ↔ \r\n 轉換。適合人類閱讀、跨平台交換。
  • 二進制模式:內存位模式原樣寫入,int 佔 4 字節,無轉換。體積小、讀寫快、適合結構體/類序列化,但不可直接文本編輯。

二、 手工文本存儲:可行但脆弱


// 寫入
std::fstream f("sprites.txt", std::ios::app);
f << profession << ' ' << weapon << '\n';

// 讀取
std::fstream f("sprites.txt", std::ios::in);
while (f >> profession >> weapon) { /* 構造對象 */ }

痛點:

  1. 字段含空格/換行需轉義或改用分隔符
  2. 結構變更(增刪字段、巢狀對象)需重寫解析邏輯
  3. 無類型信息,易誤讀
  4. 關聯數據(如玩家-裝備多對多)極難表達

三、 JSON 方案:結構化、自描述、生態完善

JSON 本質是字符串,天然適合文件存儲。推薦 nlohmann/json(單頭文件、C++11、MIT 許可證、星標 40k+)。

核心用法


#include 
using json = nlohmann::json;

// 序列化
json j;
j["profession"] = "Mage";
j["weapon"] = "truncheon";
j["level"] = 10;
std::string s = j.dump(4); // 美化縮進 4 空格

// 反序列化
json j2 = json::parse(s);
std::string prof = j2["profession"]; // 自動類型轉換
int lvl = j2.value("level", 1);      // 帶默認值的安全訪問

// 容器直接轉換
std::vector vec = {1,2,3};
json jvec = vec; // [1,2,3]
auto vec2 = jvec.get>();

實戰:精靈數據持久化


#include 
#include 
#include 
#include 
using json = nlohmann::json;

class Sprite {
public:
    std::string profession, weapon;
    Sprite(std::string p="", std::string w="") : profession(p), weapon(w) {}
    // 可選:提供 to_json/from_json 友元實現自動轉換
};

// 保存向量
bool saveSprites(const std::string& path, const std::vector>& sprites) {
    json j = json::array();
    for (auto& sp : sprites) {
        j.push_back({{"profession", sp->profession}, {"weapon", sp->weapon}});
    }
    std::ofstream f(path);
    if (!f) return false;
    f << j.dump(4);
    return true;
}

// 載入向量
bool loadSprites(const std::string& path, std::vector>& sprites) {
    std::ifstream f(path);
    if (!f) return false;
    json j = json::parse(f);
    for (auto& item : j) {
        sprites.emplace_back(std::make_shared(
            item["profession"].get(),
            item["weapon"].get()
        ));
    }
    return true;
}

優勢總結

  • Schema-free:字段增減不破壞舊數據讀取(配合 value() / contains())
  • 巢狀結構:天然支持對象嵌套、數組、關聯
  • 跨語言:Python/JS/Go 等均可直接讀寫
  • 工具鏈豐富:在線驗證、格式化、Schema 校驗(JSON Schema)

四、 進階話題:二進制序列化與性能

若數據量極大(GB 級)或極度敏感延遲,可考慮:

  • FlatBuffers / Cap'n Proto:零拷貝、隨機訪問、Schema 編譯
  • Protocol Buffers:成熟、壓縮率高、需 .proto 編譯
  • cereal / Boost.Serialization:C++ 原生、支持多態、版本控制

但對 95% 的應用場景,JSON + nlohmann/json 已足夠**,開發效率與性能平衡最佳。


總結

從 fstream 手工拼接到 nlohmann/json 一鍵序列化,核心思想是「用標準化格式隔離業務邏輯與存儲細節」。初學者先掌握文件流基礎,再引入 JSON 庫,即可在無數據庫環境下構建健壯的持久化層,為未來遷移到 SQLite/Redis/MySQL 打下良好基礎。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved