用c++向文件中写入不同的结构体

Writing different structs to a file in C++?

本文关键字:结构体 c++ 文件      更新时间:2023-10-16

我需要一种方法将三种不同类型的结构写入二进制文件,稍后必须搜索该文件。(例如,结构体A有两个字段,一个是int,一个是char;结构体B有int型和long型;我需要输出所有int值等于键盘给出的值的结构体

我理解如何编写相同类型的结构到文件以及如何搜索它们,但在这里我只是失去了,我想出的最好的事情是声明一个结构包含所有可能需要的字段,并留下那些我不需要空的,但它真的感觉错了,必须有一个更好的方法来做到这一点。

我读过二进制文件,但找不到任何相关的东西,大多数例子和教程都涉及编写一种数据类型。谁能给我指个正确的方向?

编辑:我正在寻找@Jerry_coffin所说的数据库模式,并且可能会使用现有的数据库系统之一,最好的方法,可能。谢谢大家的建议

有两种处理数据的基本方法(您还没有说哪一种适用):

  1. 我所认为的文字处理器模型:读入文件,根据需要使用/修改数据,在用户保存时将所有数据写回来(可能是自动的,即使用户没有明确要求保存)。
  2. 我认为作为一个数据库模式:你通常不打算读取整个文件到内存一次。您可以根据需要更新文件的各个部分。您可以构建文件以支持或多或少的随机访问。

如果你计划在第一个,事情是相当简单的。让你的三个结构在记忆中分开。当你把它们写出来时,你先写一种类型,然后是另一种类型,最后是第三种类型。你需要在某个地方有足够的元数据来正确地读取数据。

如果你计划第二个,它可能更复杂。这一行有几种不同的可能性:

  1. 将数据分成三个单独的文件,分别进行搜索。我知道你说你需要一个单一的文件,但如果你能做到这一点,这可能是最干净的方法。
  2. 在您的源代码中,创建这三种类型的联合,并附带一个字段来说明其余类型是哪种类型。这基本上只是将特定结构体不需要的空间留空,但使外部和内部表示之间的映射稍微简单一些。
  3. 构建一个更接近成熟的数据库系统。基本上,您需要将原始记录写入文件。然后,您将需要某种索引来告诉每个记录从哪里开始。然后,您可能需要添加至少一个索引来帮助快速轻松地查找特定记录。
  4. 使用现有的数据库系统。SQLite是一个显而易见的选择。另一个不太为人所知的是STXXL。很明显,SQLite为数据提供了一个SQL接口,这使得支持诸如特别查询之类的事情(如果需要的话)变得容易得多。STXXL提供了一个类似于标准库中的容器的接口,但是数据存储在磁盘上。这已经经过了大量的测试和优化;它通常需要相当多的努力来匹配它的性能。

至于哪一个更好:这要看情况。分离文件可能是最简单的方法。考虑到需要进行最小更改的特定需求,我可能会像2中建议的那样设计单一类型,如果需要存储大量数据,可能会使用STXXL。如果您可能需要的查询更加流畅,我可能会考虑SQLite。我会避免编写自己的数据库系统,除非您的需求非常特殊和不寻常,因此您很有可能以最小的努力为您的使用带来重大的性能改进。坦率地说,我认为这不太可能。

我建议使用protobuf

假设您创建了以下protobuf消息,例如:

message binary_info
{
    message struct_1
    {
        required int32 intValue = 1;
        required string strValue = 2;
    }
    message struct_2
    {
        required int32 intValue = 1;
        required uint64 ulongValue = 2;
    }
    message struct_3
    {
        required int32 intValue = 1;
        required uint64 ulongValue = 2;
        required string strValue = 3;
    }
    required struct_1 st1 = 1;
    required struct_2 st2 = 2;
    required struct_3 st3 = 3;
}

让google protobuf为你创建必要的文件参见开发人员指南https://developers.google.com/protocol-buffers/docs/overview

(在我的示例中,protocol在communications/proto/*处自动生成message.pb.h和message.pb.cc文件)

你可以写一个程序来保存和读取数据到文件

/*
 * main.cpp
 *
 *  Created on: 30/05/2014
 *      Author: ankit
 */
#include "communications/proto/message.pb.h"
#include <iostream>
#include <fstream>

using namespace std;
bool write_data()
{
    binary_info_struct_1* s1 = new binary_info_struct_1();
    s1->set_intvalue(1);
    s1->set_strvalue("string for s1");
    binary_info_struct_2* s2 = new binary_info_struct_2();
    s2->set_intvalue(2);
    s2->set_ulongvalue(2000);
    binary_info_struct_3* s3 = new binary_info_struct_3();
    s3->set_intvalue(3);
    s3->set_ulongvalue(3000);
    s3->set_strvalue("string for s3");
    binary_info b;
    b.set_allocated_st1(s1);
    b.set_allocated_st2(s2);
    b.set_allocated_st3(s3);
    if(!b.IsInitialized())
        return false;
    fstream output("myfile.data", ios::out | ios::binary);
    b.SerializeToOstream(&output);
    return true;
}
void read_data()
{
    fstream input("myfile.data", ios::in | ios::binary);
    binary_info b;
    b.ParseFromIstream(&input);
    cout << "struct 1, int data: " << b.st1().intvalue() << endl;
    cout << "struct 1, string data: " << b.st1().strvalue() << endl;
    cout << "struct 2, int data: " << b.st2().intvalue() << endl;
    cout << "struct 2, ulong data: " << b.st2().ulongvalue() << endl;
    cout << "struct 3, int data: " << b.st3().intvalue() << endl;
    cout << "struct 3, ulong data: " << b.st3().ulongvalue() << endl;
    cout << "struct 3, string data: " << b.st3().strvalue() << endl;
}
int main()
{
    write_data();
    read_data();
    return 0;
}

希望这对你有帮助!