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

时间:2014-08-02 04:33:27

标签: c++ arrays stream

我尝试使用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

3 个答案:

答案 0 :(得分:0)

问题可能在这里:

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

您正在为文件编写结构Perro,但您必须确保正确编写它,因为通常会像

一样
struct Foo
{
    std::string str;
};
像你想象的那样,

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

答案 1 :(得分:0)

只有在课程为POD type时,您才能使用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.size: 10, a1.ip: 0x16b4010
a2.size: 10, a2.ip: 0x16b4010
*** Error in `./test-328': double free or corruption (fasttop): 0x00000000016b4010 ***
Aborted

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

  1. 析构函数结束两次在同一地址上调用delete
  2. 分配给a2的初始内存永远不会被取消分配。
  3. 当您的某个成员变量为std::string时会发生类似情况。

答案 2 :(得分:0)

的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