【问题标题】:Writing/reading a struct from a file to a std::vector<> [duplicate]将结构从文件写入/读取到 std::vector<> [重复]
【发布时间】:2014-02-01 19:36:30
【问题描述】:

我已成功按照here 发布的答案将结构(image_info_t 类型)写入文件。 我对N 数量的image_info_t 重复该过程,所有数据都被序列化并正确添加到文件中。

我现在需要读取文件,但我需要能够读取任意数量的Mimage_info_t 结构以从文件中读取(全部按顺序)。上面引用的答案明确硬编码了从文件中读回的结构数量(即student_t master[3];)。但是,我需要这个数字是动态的。

我读过here “C++ 标准要求数组在声明其大小时使用整数文字或整数常量。改用&lt;vector&gt;

我的问题是:我该怎么做? 如何将image_info_t 结构集从文件读回std::vector

这是我用于从文件中读取 image_info_t 数据的当前(非工作)代码。

 std::ifstream input_file(path, std::ios::binary);
 const int kpts_size = kpts.size();
 feature_t master[kpts_size];  //DOES NOT WORK. If I change to `feature_t master[10];` it works.
 input_file.read((char*)&master, sizeof(master));
 input_file.close();

注意:这不是访问冲突问题,与“可能重复”的答案无关。当你这样标记它时,人们会停止阅读我的问题,这当然对任何人都没有帮助。

【问题讨论】:

  • 简单,在 StackOverflow 中搜索“c++ parse read file”。
  • 为什么标记为 C?
  • 因为如果我能以某种方式在 C 中做到这一点,那也很好。
  • 您需要显示您的姓名的定义,例如kpts,但让您感到困扰的是编译时常量和 const 限定符之间的区别。 C++11 有constexpr 告诉编译器该值可以在编译期间计算,但该声明需要已应用于计算中的每个 non-literal_constant,在本例中为kpts 的成员函数size() ,我敢打赌它没有。
  • 两者都可以。您想要哪种解决方案?

标签: c++ file struct


【解决方案1】:
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>


//Some kind of structure containing many sample data types..
typedef struct image_info
{
    char image_type;
    std::uint32_t md5_hash;
    std::string image_name;
    std::vector<std::uint8_t> bytes;
} image_info_t;


//Used for writing the above structure to a stream..
std::ostream& operator << (std::ostream& os, const image_info &entry)
{
    std::size_t image_name_size = entry.image_name.size();
    std::size_t image_bytes_size = entry.bytes.size();

    os.write(&entry.image_type, sizeof(entry.image_type));
    os.write(reinterpret_cast<const char*>(&entry.md5_hash), sizeof(entry.md5_hash));
    os.write(reinterpret_cast<const char*>(&image_name_size), sizeof(image_name_size));
    os.write(entry.image_name.c_str(), entry.image_name.size());
    os.write(reinterpret_cast<const char*>(&image_bytes_size), sizeof(image_bytes_size));
    os.write(reinterpret_cast<const char*>(&entry.bytes[0]), entry.bytes.size());
    return os;
}

//Used for reading the above structure from a stream..
std::istream& operator >> (std::istream& is, image_info &entry)
{
    std::size_t image_name_size = 0;
    std::size_t image_bytes_size = 0;

    is.read(&entry.image_type, sizeof(entry.image_type));
    is.read(reinterpret_cast<char*>(&entry.md5_hash), sizeof(entry.md5_hash));
    is.read(reinterpret_cast<char*>(&image_name_size), sizeof(image_name_size));

    entry.image_name.resize(image_name_size);
    is.read(&entry.image_name[0], image_name_size);
    is.read(reinterpret_cast<char*>(&image_bytes_size), sizeof(image_bytes_size));

    entry.bytes.resize(image_bytes_size);
    is.read(reinterpret_cast<char*>(&entry.bytes[0]), image_bytes_size);
    return is;
}

//Used for writing an array/vector of the above structure to a stream..
std::ostream& operator << (std::ostream& os, const std::vector<image_info> &entry)
{
    std::size_t entry_size = entry.size();
    os.write(reinterpret_cast<const char*>(&entry_size), sizeof(entry_size));
    for (std::size_t i = 0; i < entry_size; ++i)
        os << entry[i];

    return os;
}

//Used for reading an array/vector of the above structure from a stream..
std::istream& operator >> (std::istream& is, std::vector<image_info> &entry)
{
    std::size_t entry_size = 0;
    is.read(reinterpret_cast<char*>(&entry_size), sizeof(entry_size));
    entry.resize(entry_size);
    for (std::size_t i = 0; i < entry_size; ++i)
        is >> entry[i];
    return is;
}

int main()
{
    std::vector<image_info_t> outdata;
    std::vector<image_info_t> indata;
    image_info_t one;
    image_info_t two;

    one.image_name = "one";
    one.image_type = 'a';
    one.md5_hash = 1;
    one.bytes.push_back(0);

    two.image_name = "two";
    two.image_type = 'b';
    two.md5_hash = 2;
    two.bytes.push_back(1);

    outdata.push_back(one);
    outdata.push_back(two);

    std::fstream out("C:/Users/School/Desktop/Image_Info_T.bin", std::ios::out | std::ios::binary);

    if (out.is_open())
    {
        out << outdata;
        out.close();
    }

    std::fstream in("C:/Users/School/Desktop/Image_Info_T.bin", std::ios::in | std::ios::binary);

    if (in.is_open())
    {
        in >> indata;
    }

    std::cout<<indata[0].image_name<<"    "<<indata[1].image_name;
}

【讨论】:

  • 这看起来很有希望。我收到两个编译错误:(a)在os &lt;&lt; *it; 行,声明Invalid operands to binary expression ('std::istream') and 'value_type' (aka image image_info)。另外(2)os &lt;&lt; *it; 行声明:Invalid operand binary expression ('std::ostream') and 'const image_info'。有什么想法吗??
  • 你不应该有任何错误。它编译并运行。无论如何,我删除了迭代器,而是使用了索引运算符。它现在应该适合你了。
  • 确实可以运行!不知道区别在哪里。
【解决方案2】:

如果您想避免使用向量,您可以通过执行以下操作来初始化您的数组:

feature_t* master = new feature_t[kpts.size()];
//code
delete[] master;

或者,使用向量,您可以简单地制作 feature_t 的向量,即 IE:

std::vector<feature_t> master;

通常我发现向向量添加结构或类的最简单方法是创建它们的实例,然后填充所有值并将其添加到向量中,所以我可能会这样做:

feature_t temp;
while (getline(file, str))
{
    temp.a = ...;
    temp.b = ...;
    master.push_back(temp);
}

在 C 中,new 将替换为 malloc(或其派生函数之一),因此您可以使用:

feature_t* master = malloc(sizeof(master) * kpts.size());
//code
free(master);

【讨论】:

    猜你喜欢
    • 2012-09-04
    • 1970-01-01
    • 1970-01-01
    • 2016-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多