位置: 文档库 > C/C++ > 文档下载预览

《C++中的二进制文件操作及示例代码.doc》

1. 下载的文档为doc格式,下载后可用word或者wps进行编辑;

2. 将本文以doc文档格式下载到电脑,方便收藏和打印;

3. 下载后的文档,内容与下面显示的完全一致,下载之前请确认下面内容是否您想要的,是否完整.

点击下载文档

C++中的二进制文件操作及示例代码.doc

《C++中的二进制文件操作及示例代码》

在C++程序开发中,文件操作是核心技能之一。与文本文件不同,二进制文件以原始字节形式存储数据,不涉及字符编码转换,因此更适合处理图像、音频、序列化对象等非文本数据。本文将系统讲解C++中二进制文件的读写原理、关键类库、常见操作场景及完整示例代码,帮助开发者掌握高效处理二进制数据的方法。

一、二进制文件操作基础

二进制文件与文本文件的本质区别在于数据存储形式。文本文件将数据转换为字符序列(如ASCII或UTF-8),而二进制文件直接存储内存中的字节表示。这种特性使得二进制文件具有以下优势:

  • 存储效率高:无编码转换开销,文件体积更小
  • 读写速度快:直接操作字节流,避免解析过程
  • 数据完整性:精确还原内存中的数据结构

C++标准库通过头文件提供二进制文件操作支持,核心类包括:

  • std::ifstream:二进制输入文件流
  • std::ofstream:二进制输出文件流
  • std::fstream:同时支持读写操作的二进制文件流

打开文件时需指定二进制模式,通过在模式字符串中添加std::ios::binary标志实现。例如:

std::ofstream outFile("data.bin", std::ios::binary);
std::ifstream inFile("data.bin", std::ios::binary);

二、基本读写操作

1. 写入二进制数据

使用write()方法将内存块写入文件,其原型为:

ostream& write(const char* s, streamsize n);

参数说明:

  • s:指向数据缓冲区的指针
  • n:要写入的字节数

示例:将结构体数组写入二进制文件

#include 
#include 

struct Person {
    int id;
    char name[20];
    float salary;
};

void writeBinaryFile(const std::string& filename) {
    std::vector people = {
        {1, "Alice", 5000.0},
        {2, "Bob", 6000.0},
        {3, "Charlie", 7000.0}
    };

    std::ofstream outFile(filename, std::ios::binary);
    if (!outFile) {
        throw std::runtime_error("无法打开文件进行写入");
    }

    for (const auto& person : people) {
        outFile.write(reinterpret_cast(&person), sizeof(Person));
    }
}

2. 读取二进制数据

使用read()方法从文件读取数据到内存,原型为:

istream& read(char* s, streamsize n);

参数说明:

  • s:目标缓冲区的指针
  • n:要读取的字节数

示例:从二进制文件读取结构体数组

#include 

void readBinaryFile(const std::string& filename) {
    std::ifstream inFile(filename, std::ios::binary);
    if (!inFile) {
        throw std::runtime_error("无法打开文件进行读取");
    }

    // 获取文件大小
    inFile.seekg(0, std::ios::end);
    streampos fileSize = inFile.tellg();
    inFile.seekg(0, std::ios::beg);

    // 计算记录数量
    size_t recordCount = fileSize / sizeof(Person);
    std::vector people(recordCount);

    // 读取所有记录
    for (size_t i = 0; i (&people[i]), sizeof(Person));
    }

    // 验证读取结果
    for (const auto& person : people) {
        std::cout 

三、高级操作技巧

1. 随机访问二进制文件

通过seekg()seekp()方法实现文件指针的随机定位:

  • seekg(pos):设置输入文件指针位置
  • seekp(pos):设置输出文件指针位置
  • tellg():获取当前输入文件指针位置
  • tellp():获取当前输出文件指针位置

示例:修改二进制文件中特定记录

void updateRecord(const std::string& filename, int recordId, float newSalary) {
    std::fstream file(filename, std::ios::in | std::ios::out | std::ios::binary);
    if (!file) {
        throw std::runtime_error("无法打开文件");
    }

    Person temp;
    while (file.read(reinterpret_cast(&temp), sizeof(Person))) {
        if (temp.id == recordId) {
            // 定位到记录起始位置
            file.seekp(-static_cast(sizeof(Person)), std::ios::cur);
            temp.salary = newSalary;
            file.write(reinterpret_cast(&temp), sizeof(Person));
            return;
        }
    }

    throw std::runtime_error("未找到指定记录");
}

2. 处理变长数据

对于长度不固定的数据(如字符串),需要设计特殊的存储格式。常见方法包括:

  • 前缀长度法:先存储长度信息,再存储实际数据
  • 终止符法:使用特定字符标记数据结束

示例:存储变长字符串

struct VariableData {
    size_t length;
    char data[256]; // 假设最大长度255
};

void writeVariableData(const std::string& filename) {
    std::ofstream outFile(filename, std::ios::binary);
    std::vector<:string> strings = {"Hello", "World", "C++ Binary"};

    for (const auto& str : strings) {
        VariableData vd;
        vd.length = str.length();
        memcpy(vd.data, str.c_str(), vd.length);
        outFile.write(reinterpret_cast(&vd), sizeof(size_t) + vd.length);
    }
}

3. 内存映射文件(跨平台方案)

对于大文件处理,内存映射技术可将文件直接映射到进程地址空间,实现高效访问。Windows平台使用CreateFileMapping,Linux使用mmap。以下是跨平台封装示例:

#ifdef _WIN32
#include 
#else
#include 
#include 
#include 
#endif

class MemoryMappedFile {
public:
    MemoryMappedFile(const std::string& filename) {
#ifdef _WIN32
        handle = CreateFile(filename.c_str(), GENERIC_READ | GENERIC_WRITE,
                           0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if (handle == INVALID_HANDLE_VALUE) throw std::runtime_error("CreateFile failed");

        mapping = CreateFileMapping(handle, NULL, PAGE_READWRITE, 0, 0, NULL);
        if (!mapping) throw std::runtime_error("CreateFileMapping failed");

        data = MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
        if (!data) throw std::runtime_error("MapViewOfFile failed");
#else
        fd = open(filename.c_str(), O_RDWR);
        if (fd == -1) throw std::runtime_error("open failed");

        size = lseek(fd, 0, SEEK_END);
        data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
        if (data == MAP_FAILED) throw std::runtime_error("mmap failed");
#endif
    }

    ~MemoryMappedFile() {
#ifdef _WIN32
        UnmapViewOfFile(data);
        CloseHandle(mapping);
        CloseHandle(handle);
#else
        munmap(data, size);
        close(fd);
#endif
    }

    char* getData() const { return static_cast(data); }
    size_t getSize() const { return size; }

private:
#ifdef _WIN32
    HANDLE handle;
    HANDLE mapping;
#else
    int fd;
#endif
    void* data;
    size_t size;
};

四、完整示例:二进制文件数据库

综合上述技术,实现一个简单的二进制文件数据库系统,支持插入、查询、更新和删除操作。

#include 
#include 
#include 
#include 

struct Employee {
    int id;
    char name[50];
    double salary;
};

class BinaryDatabase {
public:
    BinaryDatabase(const std::string& filename) : filename(filename) {}

    void createTable() {
        std::ofstream outFile(filename, std::ios::binary);
        if (!outFile) {
            throw std::runtime_error("无法创建数据库文件");
        }
        // 可以在此写入表结构信息(如元数据)
    }

    void insertEmployee(const Employee& emp) {
        std::fstream file(filename, std::ios::in | std::ios::out | std::ios::binary);
        if (!file) {
            throw std::runtime_error("无法打开数据库文件");
        }

        // 定位到文件末尾
        file.seekp(0, std::ios::end);
        file.write(reinterpret_cast(&emp), sizeof(Employee));
    }

    bool findEmployee(int id, Employee& outEmp) {
        std::ifstream file(filename, std::ios::binary);
        if (!file) return false;

        Employee temp;
        while (file.read(reinterpret_cast(&temp), sizeof(Employee))) {
            if (temp.id == id) {
                outEmp = temp;
                return true;
            }
        }
        return false;
    }

    bool updateEmployee(int id, const Employee& newEmp) {
        std::fstream file(filename, std::ios::in | std::ios::out | std::ios::binary);
        if (!file) return false;

        Employee temp;
        while (file.read(reinterpret_cast(&temp), sizeof(Employee))) {
            if (temp.id == id) {
                // 定位回记录起始位置
                file.seekp(-static_cast(sizeof(Employee)), std::ios::cur);
                file.write(reinterpret_cast(&newEmp), sizeof(Employee));
                return true;
            }
        }
        return false;
    }

    bool deleteEmployee(int id) {
        // 实际删除需要重建文件,这里简化处理
        // 实际应用中应考虑使用日志结构或标记删除
        return false;
    }

private:
    std::string filename;
};

int main() {
    try {
        BinaryDatabase db("employees.dat");
        db.createTable();

        Employee emp1 = {1, "张三", 5000.0};
        Employee emp2 = {2, "李四", 6000.0};

        db.insertEmployee(emp1);
        db.insertEmployee(emp2);

        Employee found;
        if (db.findEmployee(1, found)) {
            std::cout 

五、最佳实践与注意事项

1. 字节序处理:不同系统可能使用不同字节序(大端/小端),跨平台时需统一转换

2. 数据对齐:结构体可能存在内存对齐填充,使用#pragma pack或序列化库确保跨平台兼容性

#pragma pack(push, 1)
struct PackedData {
    char a;
    int b;
    double c;
};
#pragma pack(pop)

3. 错误处理:始终检查文件操作返回值,使用异常或错误码处理IO错误

4. 性能优化

  • 批量读写替代单条记录操作
  • 使用缓冲区减少系统调用次数
  • 大文件考虑内存映射

5. 安全考虑

  • 验证二进制数据完整性(如添加校验和)
  • 防止缓冲区溢出攻击
  • 敏感数据加密存储

六、总结

C++中的二进制文件操作提供了高效、灵活的数据存储方式,特别适合处理非文本数据和需要精确控制存储格式的场景。通过掌握write()read()、随机访问和内存映射等核心技术,开发者可以构建高性能的文件存储系统。实际应用中需注意字节序、数据对齐、错误处理等关键问题,并结合具体需求选择合适的实现方案。

关键词:C++、二进制文件操作、ifstream、ofstream、fstream、write方法、read方法、随机访问、内存映射、结构体序列化

简介:本文全面讲解C++中二进制文件操作技术,涵盖基础读写、随机访问、变长数据处理、内存映射等高级技巧,提供完整数据库示例代码,并总结最佳实践与注意事项,帮助开发者掌握高效安全的二进制文件处理方法。

《C++中的二进制文件操作及示例代码.doc》
将本文以doc文档格式下载到电脑,方便收藏和打印
推荐度:
点击下载文档