如何在C 中正确写入向量到二进制文件

how to correctly write vector to binary file in c++?

本文关键字:向量 二进制文件      更新时间:2023-10-16

首先对我的英语不好。我刚加入这个论坛并搜索如何正确地将矢量写入二进制文件。我刚从这个论坛获得了这样的答案(我已经对其进行了一些修改):

#include <iostream>
#include <string.h>
#include <vector>
#include <fstream>
using namespace std;
class Student
{
public:
char m_name[30];
int m_score;
public:
Student()
{
}
Student(const char name[], const int &score)
:m_score(score)
{
    strcpy(m_name, name);
}
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));
    ofstream fout("data.dat", ios::out | ios::binary);
    fout.write((char*) &student, sizeof(student));
    fout.close();
    vector<Student> student2;
    ifstream fin("data.dat", ios::in | ios::binary);
    fin.seekg(0, ifstream::end);
    int size = fin.tellg() / sizeof (student2);
    student2.resize(size);
    fin.seekg(0, ifstream::beg);
    fin.read((char*)&student2, sizeof(student2));
    vector<Student>::const_iterator itr = student2.begin();
    while(itr != student2.end())
    {
            itr->print();
            ++itr;
    }
    fin.close();
    return 0;
}

但是当我运行它时。在我的linux薄荷上,我得到了这个结果:

Alex                 19
Maria                20
muhamed              20
Jeniffer             20
Alex                 20
Maria                21
*** glibc detected *** ./from vector to binary: corrupted double-linked list: 0x0000000000633030 ***

我是C 的新手。有些人请帮助我,过去2周陷入了这个问题。预先感谢您的答案。

您正在写作以提交向量结构,而不是其数据缓冲区。尝试将写作过程更改为:

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

在文件中存储pods 的 vector<T> ,您必须编写向量的内容,而不是向量本身。您可以使用&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。

用于函数read()和write(),您需要所谓的"普通旧数据"或" pod"。这基本上意味着阶级或结构必须没有指针,并且没有虚拟功能。向量的实现当然有指示 - 我不确定虚拟功能。

您必须编写一个函数,该函数一次存储学生(或者将一堆学生转换为阵列(而不是矢量)字节或某些此类函数 - 但这更复杂)。

您无法将非POD数据(特别是指示)编写到二进制文件的原因是,当您再次读回数据时,几乎可以肯定,您可以肯定的是,内存布局从编写时发生了变化。这变得有点像试图在商店的同一停车位停车 - 其他人下次出现时,其他人将在入口的第三位停放,因此您必须选择另一个位置。将编译器分配的记忆视为停车位,以及学生信息为汽车。

[从技术上讲,在这种情况下,更糟糕的是 - 您的向量实际上并不包含班级中的学生,这是您写在文件中的内容,因此您甚至没有保存有关学生的信息,只是有关其所在位置的信息(停车位数)]

您可能无法用二进制(您正在做的方式)写入任何std::vector,因为该模板包含内部指针,编写和重新阅读它们是毫无意义的。

一些一般建议:

  • 不要在二进制中写入任何STL模板容器(例如std::vectorstd::map),它们肯定包含您真正不想按原样编写的内部指针。如果您真的需要写它们,请实现自己的写作和阅读例程(例如使用STL迭代器)。

  • 避免不小心使用strcpy。如果名称具有30多个字符,则您的代码将崩溃。至少,使用strncpy(m_name, name, sizeof(m_name));(但即使在30个字符的名称中也很糟糕)。实际上,m_name应该是std::string

  • 明确序列化您的容器类(通过处理每个有意义的成员数据)。您可以考虑使用JSON符号(或YAML,甚至XML)来序列化。它为您提供了一种文本转储格式,您可以使用标准编辑器(例如emacsgedit)轻松检查。您会发现很多序列化的免费库,例如jsoncpp和许多其他。

  • 学习使用g++ -Wall -g编译并使用gdb调试器和valgrind内存泄漏检测器;还要学习使用make并编写您的Makefile-S。

  • 利用Linux是免费软件的优势,因此您可以查看其源代码(即使STL标头很复杂,也可能需要研究STDC 实现)。