将对象数组写入和读取到二进制文件



我尝试使用fstream,虽然显然编译,程序崩溃。请告诉我上面的代码有什么问题,我应该怎么做才能纠正它

我想从二进制文件中恢复miperro5[]的所有元素到一个新的数组miperro6[]。怎样才能解决问题?

#include <stdio.h>
#include <iostream>
#include <Perro.hpp>
#include <fstream>
using std::cout;
using std::endl;
int main(int argc, char **argv)
{
    Perro miperro5[5];
    Perro miperro6[5];
    miperro5[2].nombre = "lucky";
    std::ofstream myfile;
    myfile.open("example.bin", std::ios::out | std::ios::app | std::ios::binary);
    for (int i = 0; i < 5; i++){
        myfile.write(reinterpret_cast<char *>(&miperro5[i]), sizeof(Perro));
    }
    myfile.close();
    std::ifstream myfile2;
    myfile2.open("example.bin", std::ios::in | std::ios::binary);
    for (int j = 0; j < 5; j++){
        myfile2.read(reinterpret_cast<char *>(&miperro6[j]), sizeof(Perro));
    }
    myfile2.close();
    for (int z = 0; z < 5; z++){
        cout << miperro6[z].nombre << endl;
    }
    std::cin.get();
    return 0;
}

这是Perro.hpp

#ifndef PERRO_HPP
#define PERRO_HPP
#include <string>
class Perro
{
public:
    Perro();
    ~Perro();
    void ladrar();
    void comer();
    std::string nombre;
    int edad;
    int arra[2];

};
#endif // PERRO_HPP

只能在类为POD类型时使用fwritefread

Perro不是POD类型,因为它有一个类型为std::string的成员变量。

让我用一个简单的例子来说明这个问题。假设你有:

#include <iostream>
#include <fstream>
struct A
{
   A(int s) : ip(new int[s]), size(s) {}
   ~A() { delete [] ip; }
   int* ip;
   int size;
};
int main()
{
   A a1(10);
   A a2(5);
   std::cout << "a1.size: " << a1.size << ", a1.ip: " << a1.ip << std::endl;
   std::ofstream myfile;
   myfile.open("example.bin", std::ios::out | std::ios::binary);
   myfile.write(reinterpret_cast<char *>(&a1), sizeof(A));
   myfile.close();
   std::ifstream myfile2;
   myfile2.open("example.bin", std::ios::in | std::ios::binary);
   myfile2.read(reinterpret_cast<char *>(&a2), sizeof(A));
   myfile2.close();
   std::cout << "a2.size: " << a2.size << ", a2.ip: " << a2.ip << std::endl;
   return 0;
}

当我运行程序时,我得到以下输出:

<>之前a1。尺寸:10号,a1号。知识产权:0 x16b4010a2。尺寸:10,a2。知识产权:0 x16b4010***输入错误。/test-328': double free or corruption (fasttop): 0x00000000016b4010 ***流产之前

这里发生的事情是a1.ip的二进制值被写入文件,并将相同的二进制值读入a2.ip。在读取之后,a1.ipa2.ip都指向相同的内存位置。这会导致两个问题:

  1. 析构函数终止对同一地址两次调用delete
  2. a2分配的初始内存永远不会被释放。

当您的成员变量之一是std::string时,也会发生类似的情况。

问题可能在这里:

myfile.write(reinterpret_cast<char *>(&miperro5[i]), sizeof(Perro));

你正在写一个结构体Perro到文件,但你必须确保你写得正确,因为一般情况下,像

这样的东西
struct Foo
{
    std::string str;
};

不会像您想象的那样写入磁盘。只有只包含普通旧数据(POD)的结构可以像您所做的那样编写,其余的必须手动编写每个字段。如果您想通过对象序列化简化您的生活,请查找boost::serialization

main.cpp

#include <stdio.h>
#include <iostream>
#include <fstream>
#include "Perro.hpp"
using std::cout;
using std::endl;
int main(int argc, char **argv)
{
    Perro miperro5[5];
    Perro miperro6[5];
    miperro5[2].nombre = "lucky";
    std::ofstream myfile;
    myfile.open("example.bin", std::ios::out | std::ios::app | std::ios::binary);
    for (int i = 0; i < 5; i++){
        myfile << miperro5[i];
    }
    myfile.close();
    std::ifstream myfile2;
    myfile2.open("example.bin", std::ios::in | std::ios::binary);
    for (int j = 0; j < 5; j++){
        myfile2 >> miperro6[j];
    }
    myfile2.close();
    for (int z = 0; z < 5; z++){
        cout << miperro6[z].nombre << endl;
    }
    std::cin.get();
    return 0;
}

Perro.hpp

#ifndef PERRO_HPP
#define PERRO_HPP
#include <string>
#include <ostream>
#include <istream>
class Perro
{
public:
    Perro() {};
    ~Perro() {};
    void ladrar();
    void comer();
    std::string nombre;
    int edad;
    int arra[2];
};
std::ostream & operator<<(std::ostream & ostrm, const Perro & src)
{
    // nombre
    std::string::size_type cch = src.nombre.length();
    ostrm // std::string is not a primitive type, so we need to do a (sort of) deep copy.
        .write(reinterpret_cast<const char *>(&cch), sizeof(std::string::size_type))
        << src.nombre.c_str() // or use unformatted output `write`
    ;
    // edad, arra[2]
    ostrm
        .write(reinterpret_cast<const char *>(&src.edad), sizeof(int)) // edad
        .write(reinterpret_cast<const char *>(&src.arra), sizeof(int) * 2) // arra[2]
    ;
    return ostrm;
}
std::istream & operator>>(std::istream & istrm, Perro & dst)
{
    // Read the string back.
    std::string::size_type cchBuf;
    istrm.read(reinterpret_cast<char *>(&cchBuf), sizeof(std::string::size_type));
    char * buf = new char[cchBuf];
    istrm.read(buf, cchBuf);
    dst.nombre.assign(buf, cchBuf);
    delete [] buf;
    // Read other data members of primitive data type.
    istrm
        .read(reinterpret_cast<char *>(&dst.edad), sizeof(int)) // edad
        .read(reinterpret_cast<char *>(&dst.arra), sizeof(int) * 2) // arra[2]
    ;
    // Return the stream so it can be examined on its status.
    return istrm;
}
#endif // PERRO_HPP

相关内容

  • 没有找到相关文章

最新更新