繁体   English   中英

读取和写入结构向量到文件

[英]reading and writing a vector of structs to file

我读了一些关于Stack Overflow的文章,以及其他一些有关将向量写入文件的站点。 我已经实现了自己的工作方式,但遇到了一些麻烦。 结构中的数据成员之一是类字符串,并且当重新读入向量时,该数据将丢失。 同样,在编写第一个迭代之后,其他迭代也会导致malloc错误。 如何修改下面的代码,以实现将向量保存到文件中所需的功能,然后在程序再次启动时将其读回? 当前,读取是在一个类的构造函数中完成的,在析构函数中进行写入的,该类的唯一数据成员是向量,但具有操作该向量的方法。

这是我的读/写方法的要点。 假设vector<element> elements ...

读:

ifstream infile;
infile.open("data.dat", ios::in | ios::binary);
infile.seekg (0, ios::end);
elements.resize(infile.tellg()/sizeof(element));
infile.seekg (0, ios::beg);
infile.read( (char *) &elements[0], elements.capacity()*sizeof(element));
infile.close();

写:

ofstream outfile;
outfile.open("data.dat", ios::out | ios::binary | ios_base::trunc);
elements.resize(elements.size());
outfile.write( (char *) &elements[0], elements.size() * sizeof(element));
outfile.close();

结构元素:

struct element {
int id;
string test;
int other;        
};

在C ++中,通常不能像这样直接将内存直接读取和写入磁盘。 特别是,您的struct element包含一个string ,它是非POD数据类型,因此不能直接访问。

进行思想实验可能有助于澄清这一点。 您的代码假定所有element值均大小相同。 如果其中一个string test值比您预期的长,会发生什么? 您的代码如何知道在读写磁盘时使用什么大小?

您将需要阅读有关序列化的更多信息,以了解如何处理序列化

您的代码假定所有相关数据都直接存在于向量内部,而字符串是固定大小的对象,该对象的指针可以在堆中增加其大小可变的内容。 您基本上是在保存指针,而不是文本。 您应该编写一些字符串序列化代码,例如:

bool write_string(std::ostream& os, const std::string& s)
{
    size_t n = s.size();
    return os.write(n, sizeof n) && os.write(s.data(), n);
}

然后,您可以为您的结构编写序列化例程。 有几种设计选项:-许多人喜欢声明可以容纳std :: ostream的Binary_IStream / Binary_OStream类型,但可以使用不同的类型来创建单独的序列化例程集ala:

operator<<(Binary_OStream& os, const Some_Class&);

或者,您可以只在处理二进制序列化时放弃通常的流符号,而可以使用函数调用符号。 显然,让相同的代码正确输出二进制序列化和人类可读的序列化是很好的,因此基于操作员的方法很有吸引力。

如果要序列化数字,则需要确定是以二进制格式还是以ASCII进行序列化。 对于纯二进制格式,在需要可移植的情况下(甚至在同一OS上在32位和64位之间进行编译),您可能还需要付出一些努力来编码和使用类型大小的元数据(例如int32_t或int64_t?)。作为字节序(例如,考虑网络字节顺序和ntohl()系列功能)。 使用ASCII可以避免这些注意事项,但是它的长度可变,并且写入/读取的速度可能较慢。 在下面,我随意地将ASCII与'|'一起使用 数字的终止符。

bool write_element(std::ostream& os, const element& e)
{
    return (os << e.id << '|') && write_string(os, e.test) && (os << e.other << '|');
}

然后为您的向量:

os << elements.size() << '|';
for (std::vector<element>::const_iterator i = elements.begin();
     i != elements.end(); ++i)
    write_element(os, *i);

阅读此内容:

std::vector<element> elements;
size_t n;
if (is >> n)
    for (int i = 0; i < n; ++i)
    {
        element e;
        if (!read_element(is, e))
            return false; // fail
        elements.push_back(e);
   }

...需要...

bool read_element(std::istream& is, element& e)
{
    char c;
    return (is >> e.id >> c) && c == '|' &&
           read_string(is, e.test) &&
           (is >> e.other >> c) && c == '|';
}

...和...

bool read_string(std::istream& is, std::string& s)
{
    size_t n;
    char c;
    if ((is >> n >> c) && c == '|')
    {
        s.resize(n);
        return is.read(s.data(), n);
    }
    return false;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM