Skip to content

二进制序列化 ​

C++ 支持以二进制模式读写文件,用于存储原始二进制数据(如结构体、图像、音频等)。

基本二进制读写 ​

写入二进制 ​

cpp
#include <fstream>

int num = 42;
double pi = 3.14159;
char c = 'A';

std::ofstream out("data.bin", std::ios::binary);
out.write(reinterpret_cast<const char*>(&num), sizeof(num));
out.write(reinterpret_cast<const char*>(&pi), sizeof(pi));
out.write(&c, sizeof(c));
out.close();

读取二进制 ​

cpp
#include <fstream>

int num;
double pi;
char c;

std::ifstream in("data.bin", std::ios::binary);
in.read(reinterpret_cast<char*>(&num), sizeof(num));
in.read(reinterpret_cast<char*>(&pi), sizeof(pi));
in.read(&c, sizeof(c));
in.close();

结构体序列化 ​

简单结构体 ​

cpp
struct Person {
    char name[20];
    int age;
    double salary;
};

// 写入
Person p = {"Alice", 30, 5000.0};
std::ofstream out("person.bin", std::ios::binary);
out.write(reinterpret_cast<const char*>(&p), sizeof(p));
out.close();

// 读取
Person readP;
std::ifstream in("person.bin", std::ios::binary);
in.read(reinterpret_cast<char*>(&readP), sizeof(readP));
in.close();

带字符串的结构体(C++ 字符串) ​

cpp
#include <fstream>
#include <string>

struct Person {
    std::string name;  // 注意:二进制序列化 string 需要特殊处理
    int age;
};

// 简单方式:逐字段序列化
void writePerson(std::ofstream& out, const Person& p) {
    // 写入字符串长度
    size_t len = p.name.size();
    out.write(reinterpret_cast<const char*>(&len), sizeof(len));
    // 写入字符串内容
    out.write(p.name.c_str(), len);
    // 写入其他字段
    out.write(reinterpret_cast<const char*>(&p.age), sizeof(p.age));
}

Person readPerson(std::ifstream& in) {
    Person p;
    size_t len;
    in.read(reinterpret_cast<char*>(&len), sizeof(len));
    p.name.resize(len);
    in.read(&p.name[0], len);
    in.read(reinterpret_cast<char*>(&p.age), sizeof(p.age));
    return p;
}

字节序问题 ​

不同系统可能使用不同的字节序(endianness),网络传输时需注意:

cpp
#include <cstdint>

// 大端字节序(网络序)
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);

// 小端转大端
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

序列化最佳实践 ​

使用 RAII 管理文件 ​

cpp
#include <fstream>
#include <memory>

class BinaryFile {
public:
    BinaryFile(const std::string& path, std::ios::mode mode) {
        if (mode & std::ios::out) {
            stream = std::make_unique<std::ofstream>(path, std::ios::binary);
        } else {
            stream = std::make_unique<std::ifstream>(path, std::ios::binary);
        }
    }

    std::fstream& get() { return *stream; }

private:
    std::unique_ptr<std::fstream> stream;
};

// 使用
{
    BinaryFile out("data.bin", std::ios::out);
    int x = 100;
    out.get().write(reinterpret_cast<const char*>(&x), sizeof(x));
} // 自动关闭

检查读写是否成功 ​

cpp
std::ofstream out("data.bin", std::ios::binary);
int x = 42;
out.write(reinterpret_cast<const char*>(&x), sizeof(x));

if (!out) {
    std::cerr << "写入失败!" << std::endl;
}

std::ifstream in("data.bin", std::ios::binary);
int y;
in.read(reinterpret_cast<char*>(&y), sizeof(y));

if (!in) {
    std::cerr << "读取失败或数据不完整!" << std::endl;
}

// 检查实际读取的字节数
std::streamsize bytesRead = in.gcount();
std::cout << "实际读取了 " << bytesRead << " 字节" << std::endl;