0

想象一下,我有一个 class 的对象Product,它的成员变量如下:price, name, etc.。假设我有 10 个这样的 Product 对象。现在我想把所有 10 个都写到某个文件Products.dat中。稍后我想说从文件中检索第 6 个产品。它通常是如何在 C++ 中实现的?(我只是对检索部分感兴趣)。

4

3 回答 3

2

您检索数据集的方式取决于您存储数据的方式。如果您有一个固定大小的结构,您可以使用fseek(file, dataSize * RecordNr, SEEK_SET);将文件定位在预期的偏移量,然后从那里读取数据。这将要求,例如,您的字符串name具有固定的最大长度,并且记录始终以该已知长度存储。

如果您的数据结构是可变长度的,那么您将不得不计算每条记录的长度,或者您必须单独读取它们。在这种情况下,更好的选择可能是使用一些现有的库,如 sqlite 或 XML 来管理您的文件内容。

可变长度结构的另一种替代方法是将第二个文件作为索引来维护,您可以在其中存储每条记录的偏移量。

如果您只需要这么少的记录来进行某些分配,则使用具有固定长度记录的 fseek 可能就足够了。

更新

为了使用固定大小的记录,您应该创建没有任何指针的数据结构。否则,您将不得不单独读取/写入这些成员。

例如:

class Product
{
    double Price;
    int Category;
    char Name[50];
    char ArticleId[10];
};

代替

class Product
{
    double Price;
    int Category;
    char *Name;
    char *ArticleId;
};

但是您应该知道,这样一个固定的结构使您的程序只能在您编写的平台上运行。您无法轻松地将数据文件复制到其他平台。如果您打算与其他平台兼容,则不应使用此方法,因为它会使移植更加困难。

于 2013-06-24T06:58:35.637 回答
2

我建议您首先使用文件格式,例如:

39.28
product name
other data
47.12
another product name
other data
...

然后,您可以使用ifstream对象读取文件,使用 一次获取一个文本行getline(),并使用operator>>数值获取数值(但请注意忽略该行的其余部分,以免下一getline行读取空行) . 跟踪您正在阅读的字段和记录,直到达到所需的记录。

如果您需要更快的访问速度,则需要使用固定宽度的字段,这需要更多关于输出格式的知识……最好在第二步中学习。使用固定宽度字段,您可以使用 ifstream 上的 seek 函数直接跳转到相关数据,然后使用getlineor开始读取operator>>,甚至ifstream::read().

编辑:根据评论使示例更加明确 - 并添加 product_index 字段。这可能需要一些调试/调整,但基本的想法是希望有用的......

struct Product
{
    double price_;
    double product_index_;
    std::string product_name_;
    std::string other_data_;

    friend std::ostream& operator<<(std::ostream& os, const Product& p)
    {
        return os << p.price_ << '\n'
                  << p.product_index_ << '\n'
                  << p.product_name_ << '\n'
                  << p.other_data << '\n';
    }

    friend std::istream& operator>>(std::ostream& is, Product& p)
    {
        is >> p.price_ >> p.product_index_;
        is.ignore(std::numeric_limits<streamsize>::max(), '\n');
        getline(is, p.product_name_);
        getline(p.other_data);
        return is;
    }
};

    // to read your input file...
    if (ifstream input("input.dat"))
    {
        Product p;
        while (input >> p)
            do_something_with(p);

        if (!input.eof())
            std::cerr << "error during parsing of input file\n";
    }
    else
        std::cerr << "error opening input file\n";
于 2013-06-24T06:59:37.143 回答
1

如果您认真对待您的任务并关心性能、可移植性和二进制兼容性,请考虑将 NoSQL 数据库(例如MongoDBProtocol Buffers )与任何其他 NoSQL 数据库一起使用。

打开与数据库的连接,该连接在单独的进程中运行:

mongo::DBClientConnection c;
c.connect("localhost");

查询数据库如下所示:

std::unique_ptr<DBClientCursor> cursor =
     c.query("mystore.products", BSONObj());
while (cursor->more()) {
     BSONObj p = cursor->next();
     std::cout << p.getStringField("name") << std::endl;

按照“C++ 驱动程序入门”的思路

并将对象插入数据库:

BSONObj p = BSON( "name" << "A nice book" << "price" << 42 );
c.insert("mystore.products", p);

更新更多:如果您只需要序列化,但没有高效的查询、事务等,那么您“仅仅”需要一个好的序列化策略:JSONBSONProtocol BuffersMessagePackXMLBoost.Serializationcpgf可能会有所帮助

于 2013-06-24T07:04:20.653 回答