感谢Mats Petersson关于如何将矢量复制到数组的解释,这看起来很有用。这是代码snipet:
#include <iostream>
#include <string.h>
#include <vector>
#include <fstream>
using namespace std;
class Student
{
private:
char m_name[30];
int m_score;
public:
Student()
{
}
Student(const Student& copy)
{
m_score = copy.m_score; //wonder why i can use this statment as
strncpy(m_name, copy.m_name, 30); //declare it private
}
Student(const char name[], const int &score)
:m_score(score)
{
strncpy(m_name, name, 30);
}
void print() const
{
cout.setf(ios::left);
cout.width(20);
cout << m_name << " " << m_score << endl;
}
};
int main()
{
vector<Student> student;
student.push_back(Student("Alex",19));
student.push_back(Student("Maria",20));
student.push_back(Student("muhamed",20));
student.push_back(Student("Jeniffer",20));
student.push_back(Student("Alex",20));
student.push_back(Student("Maria",21));
{
Student temp[student.size()];
unsigned int counter;
for(counter = 0; counter < student.size(); ++counter)
{
temp[counter] = student[counter];
}
ofstream fout("data.dat", ios::out | ios::binary);
fout.write((char*) &temp, sizeof(temp));
fout.close();
}
vector<Student> student2;
ifstream fin("data.dat", ios::in | ios::binary);
{
fin.seekg(0, ifstream::end);
int size = fin.tellg() / sizeof (Student);
Student temp2[size];
fin.seekg(0, ifstream::beg);
fin.read((char*)&temp2, sizeof(temp2));
int counter;
for(counter = 0; counter <6; ++counter)
{
student2.push_back(temp2[counter]);
}
fin.close();
}
vector<Student>::iterator itr = student2.begin();
while(itr != student2.end())
{
itr->print();
++itr;
}
return 0;
}
但我客人这种方法会浪费大量内存并且很麻烦。也许我会考虑用ocelot和其他建议写一下先生。 谢谢大家的回答。
答案 0 :(得分:18)
要在文件中存储vector<T>
PODs ,您必须编写向量的内容,而不是向量本身。您可以使用&vector[0]
访问原始数据,第一个元素的地址(假设它包含至少一个元素)。要获取原始数据长度,请将向量中的元素数乘以一个元素的大小:
strm.write(reinterpret_cast<const char*>(&vec[0]), vec.size()*sizeof(T));
从文件中读取向量时同样适用;元素计数是总文件大小除以一个元素的大小 (假设您只在文件中存储了一种类型的POD):
const size_t count = filesize / sizeof(T);
std::vector<T> vec(count);
strm.read(reinterpret_cast<char*>(&vec[0]), count*sizeof(T));
这仅在您可以根据文件大小计算元素数量时才有效(如果您只存储一种类型的POD或所有向量包含相同数量的元素)。如果你有不同POD长度不同的向量,你必须在写入原始数据之前将向量中的元素数写入文件。
此外,当您在不同系统之间以二进制形式传输数字类型时,请注意endianness。
答案 1 :(得分:9)
您正在写入矢量结构的文件,而不是其数据缓冲区。尝试将更改程序改为:
ofstream fout("data.dat", ios::out | ios::binary);
fout.write((char*)&student[0], student.size() * sizeof(Student));
fout.close();
而不是从文件大小计算向量的大小,最好先写入向量大小(对象的数量)。在这种情况下,您可以将同一文件写入其他数据。
size_t size = student.size();
fout.write((char*)&size, sizeof(size));
答案 2 :(得分:3)
你可能无法以二进制(你正在做的方式)写任何std::vector
,因为该模板包含内部指针,写入和重新读取它们毫无意义。
一些一般性建议:
不要在二进制文件中写入任何STL模板容器(如std::vector
或std::map
),它们肯定包含你真正不想写的内部指针。如果你真的需要编写它们,请实现自己的编写和读取例程(例如使用STL迭代器)。
避免谨慎使用strcpy
。如果名称超过30个字符,您的代码将崩溃。至少,使用strncpy(m_name, name, sizeof(m_name));
(但即使这对于30个字符的名称也会很糟糕)。实际上,m_name
应为std::string
。
显式序列化您的容器类(通过处理每个有意义的成员数据)。您可以考虑使用JSON表示法(或者可能是YAML,或者甚至是XML - 我发现它太复杂,所以不建议)进行序列化。它为您提供了一种文本转储格式,您可以使用标准编辑器轻松检查该格式(例如emacs
或gedit
)。你会发现许多序列化的免费库,例如jsoncpp和其他许多人。
学习使用g++ -Wall -g
进行编译并使用gdb
调试器和valgrind
内存泄漏检测器;还学习使用make
并撰写Makefile
- s。
利用Linux是免费软件,因此您可以查看其源代码(即使STL标头很复杂,您也可能希望学习stdc ++实现)。
答案 3 :(得分:2)
对于函数read()和write(),您需要所谓的“普通旧数据”或“POD”。这基本上意味着类或结构必须在它们内部没有指针,并且没有虚函数。 vector的实现肯定有指针 - 我不确定虚函数。
你必须编写一个一次存储一个学生的函数(或者将一堆学生翻译成一个字节的数组[不是矢量]或者一些这样的 - 但这更复杂)。
您无法将非POD数据(特别是指针)写入二进制文件的原因是,当您再次读取数据时,几乎可以肯定的是,内存布局从您编写时就已经发生了变化。它有点像试图停在商店的同一个停车位 - 当你下次出现时,其他人会从入口处停在第三个位置,所以你必须选择另一个位置。将编译器分配的内存视为停车位,将学生信息视为汽车。
[从技术上讲,在这种情况下,更糟糕的是 - 你的向量实际上并不包含课堂内的学生,这就是你写入文件的内容,所以你甚至没有保存关于学生的信息,只是关于他们所在位置的信息(停车位的数量)]