2010-11-29 59 views
1

我已阅读了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元件:

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

你用什么C++学习资料告诉你这样做文件访问? – 2010-11-29 01:18:41

+0

这是一项家庭作业的一部分,它要求我们使用fstream将矢量数据读/写到文件中。由于我们没有完全覆盖向班级中的文件进行复杂的矢量写入,因此我阅读了fstream文档等,并在线查看了示例。我决定用二进制文字编写是最简单的方法。调整大小等某些细节是我选择要限制的文件大小。我们没有正式的书或教材。我们有一些在线笔记,但它们并不像实现我所需要的那么详细。 – 2010-11-29 01:38:24

回答

6

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

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

有关如何处理此问题的更多信息,您需要阅读serialization

1

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

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); 
} 

然后您可以为您的结构编写序列化例程。有几个设计方案: - 很多人都喜欢声明Binary_IStream/Binary_OStream类型,可以容纳一个std :: ostream的,但作为一个独特的类型可以用来创建ALA一组单独的序列化例程:

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

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

如果您序列化数字,您需要决定是以二进制格式还是ASCII格式。对于需要可移植性的纯二进制格式(甚至在同一操作系统上的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; 
}