想象一下,我有一个 class 的对象Product
,它的成员变量如下:price, name, etc.
。假设我有 10 个这样的 Product 对象。现在我想把所有 10 个都写到某个文件Products.dat
中。稍后我想说从文件中检索第 6 个产品。它通常是如何在 C++ 中实现的?(我只是对检索部分感兴趣)。
3 回答
您检索数据集的方式取决于您存储数据的方式。如果您有一个固定大小的结构,您可以使用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;
};
但是您应该知道,这样一个固定的结构使您的程序只能在您编写的平台上运行。您无法轻松地将数据文件复制到其他平台。如果您打算与其他平台兼容,则不应使用此方法,因为它会使移植更加困难。
我建议您首先使用文件格式,例如:
39.28
product name
other data
47.12
another product name
other data
...
然后,您可以使用ifstream
对象读取文件,使用 一次获取一个文本行getline()
,并使用operator>>
数值获取数值(但请注意忽略该行的其余部分,以免下一getline
行读取空行) . 跟踪您正在阅读的字段和记录,直到达到所需的记录。
如果您需要更快的访问速度,则需要使用固定宽度的字段,这需要更多关于输出格式的知识……最好在第二步中学习。使用固定宽度字段,您可以使用 ifstream 上的 seek 函数直接跳转到相关数据,然后使用getline
or开始读取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";
如果您认真对待您的任务并关心性能、可移植性和二进制兼容性,请考虑将 NoSQL 数据库(例如MongoDB或Protocol 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;
并将对象插入数据库:
BSONObj p = BSON( "name" << "A nice book" << "price" << 42 );
c.insert("mystore.products", p);
更新更多:如果您只需要序列化,但没有高效的查询、事务等,那么您“仅仅”需要一个好的序列化策略:JSON、BSON、Protocol Buffers、MessagePack或XML、Boost.Serialization或cpgf可能会有所帮助