简体   繁体   English

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

[英]Write and read array of objects to binary file?

I have tried using fstream and although apparently compiled, the program crash. 我曾尝试使用fstream ,尽管显然已编译,但程序崩溃。 Please tell me what is wrong in above code and what should I do to correct it 请告诉我上面代码中有什么问题,我应该怎么做才能纠正它

I want to recover all elements of miperro5[] from the binary file into a new array miperro6[] . 我想将二进制文件中的miperro5[]所有元素恢复到新数组miperro6[] As might fix it? 如可能解决?

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

This is Perro.hpp 这是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

The problem is probably here: 问题可能在这里:

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

You are writing a struct Perro to file, but you have to make sure that you write it correctly, since in general the something like 您正在将Perro结构写入文件,但必须确保正确编写,因为通常情况下,类似

struct Foo
{
    std::string str;
};

will not be written on the disk as you would think. 不会像您想的那样写入磁盘。 Only structs containing ONLY plain old data (POD) can be written as you are doing, for the rest you have to manually write each field. 在执行操作时,只能写入仅包含纯旧数据(POD)的结构,其余的则必须手动写入每个字段。 Look for boost::serialization if you want to simplify your life with object serialization. 如果您想简化对象序列boost::serialization ,请寻找boost::serialization serialization。

You can use fwrite and fread the way you are using only when a class is a POD type . 仅当类为POD类型时,才可以使用fwritefread方式。

Perro is not a POD type since it has a member variable of type std::string . Perro不是POD类型,因为它具有类型为std::string的成员变量。

Let me use a simpler example to illustrate the problem. 让我用一个简单的例子来说明这个问题。 Let's say you have: 假设您有:

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

When I run the program, I get the following output: 运行程序时,将得到以下输出:

a1.size: 10, a1.ip: 0x16b4010
a2.size: 10, a2.ip: 0x16b4010
*** Error in `./test-328': double free or corruption (fasttop): 0x00000000016b4010 ***
Aborted

What happened here is that binary value of a1.ip was written out to the file and the same binary value was read into a2.ip . 这里发生的是将a1.ip二进制值写到文件中,并将相同的二进制值读入a2.ip After the read, both a1.ip and a2.ip point to the same memory location. 读取后, a1.ipa2.ip指向相同的存储位置。 These causes two problems: 这会导致两个问题:

  1. The destructor ends of calling delete on the same address twice. 析构函数在同一地址两次调用delete结束。
  2. The initial memory allocated for a2 never gets deallocated. 分配给a2的初始内存永远不会被释放。

Similar things happen when one of your member variables is a std::string . 当您的成员变量之一是std::string时,也会发生类似的情况。

main.cpp 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 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM