从cpp文件中读入对象

Read in objects from file in cpp

我有一个人 class 和一只宠物 class。 人有名字和年龄。 pet 有一种动物及其颜色

人class持有宠物向量

我正在尝试从文件中读取数据以填充人物对象的向量(每个人都有自己的宠物向量)

文件结构如下:

sally 32
cat brown
-1

tom 49
dog white
dog brown
-1

sue 54
lizard green
-1

emily 18
cat white
cat brown
cat black
-1

-1 为"flag" 表示输入完毕

我不知道如何解释每个人宠物数量的差异,更不用说如何在 -1 处停止了

这是我目前的代码:(适用于 linear/without 宠物数量可变的数据文件)

void fillArray(vector<Person> &people){
    ifstream peopleFile("people.dat");
    string name;
    int age;
    string animal;
    string colour;

    while(!peopleFile.eof()){
        peopleFile>>name>>age;
        peopleFile>>animal>>colour;
        Person p(name,age);
        Pet pet(animal,colour);
        p.addPet(pet);
        people.push_back(p);
        ..
    }
}

没那么复杂。我们会将大问题分解成小问题,然后逐个解决。

我们将使用 iostream 提取器运算符从流中获取所有数据。对于 Pet class,我们将首先阅读完整的行,包括动物和颜色。为此,我们将使用最常用的 std::getline

我们总是先阅读完整的行以避免行尾出现问题。然后我们将刚刚读取的行塞入std::istringstream。这也是一个流,有了它,我们可以像从任何其他流中一样读取字符串。

我们从该流中简单地提取姓名和年龄。没那么复杂。

读一个人要复杂一点。文件中的新条目可以以空行开头。所以我们会先读取空行并丢弃它们。

然后,我们再次将此行放在 std::istringstream 中,然后提取姓名和年龄。简单。

接下来,可能有一只或多只宠物。分隔符是包含 -1 的行。因此,我们在 while 循环中读取行,直到该行为 -1。如果是-1,我们就不执行循环体了。

如果它不是-1,而是有效数据,我们再次将该行放入 std::istringstream 并从此流中提取一个 Pet。 Pet pTemp; iss2 >> pTemp; 行将调用宠物提取器操作员。然后我们将新宠物添加到我们的内部 std::vector.

基本上就这些了。

在 main 中,我们打开文件并检查是否有效。

然后我们定义一个vector类型的变量(persons),并使用它的范围构造函数来初始化它。作为范围构造函数的迭代器,我们将为 Person class 使用 std::istream_iterator。这将简单地调用 Person 提取器,直到读取所有数据。所以,我们最后会用一行读取所有数据。

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>

struct Pet {
    std::string animal{};
    std::string color{};
};

// Define Extractor for a pet
std::istream& operator >> (std::istream& is, Pet& p) {

    // Read a line containing the animal name and the color
    if (std::string line{}; std::getline(is, line)) {

        // Now put line in istringstream, so that we can use iostream operations to extract data
        std::istringstream iss{ line };

        // Extract info for one pet
        iss >> p.animal >> p.color;
    }
    return is;
}

// Define Inserter for a pet for easier output
std::ostream& operator << (std::ostream & os, const Pet & p) {
    return os << "Pet:   \t" << p.animal << "\t\tAnimal: \t " << p.color << '\n';
}


struct Person {
    std::string name{};
    unsigned int age;
    std::vector<Pet> pets;
};

// Define a extractor for a person
std::istream& operator >> (std::istream& is, Person& p) {
    std::string line{};
    // Read empty strings and discard them
    while (std::getline(is, line) && line == "")
        ; 
    if (is) {
        // Read a line containing the name and the age
        // Now put line in istringstream, so that we can use iostream operations to extract data
        std::istringstream iss{ line };

        // Extract name and age
        iss >> p.name >> p.age;
        p.pets.clear();

        // Next, we want to read all pets, line by line, until we find -1
        while (std::getline(is, line) && line != "-1") {

            // Now put line in istringstream, so that we can use iostream operations to extract data
            std::istringstream iss2{ line };

            // Extract pet from this line. Call overwritten Extractor from Pet
            Pet pTemp; iss2 >> pTemp;

            // Add new pet to vector
            p.pets.push_back(std::move(pTemp));
        }
    }
    return is;
}

// Define Inserter for a person for easier output
std::ostream& operator << (std::ostream& os, const Person& p) {
    os << "\n\nName:\t" << p.name << "\t\tAge: \t" << p.age <<'\n';
    for (const Pet& pet : p.pets) os << pet;
    return os;
}

int main() {
    // Open file and check, if it could be opened
    if (std::ifstream datFileStream{ "r:\people.dat" }; datFileStream) {

        // Read complete source file with the vectors range constructor
        std::vector persons(std::istream_iterator<Person>(datFileStream), {});

        // Show debug output
        for (const Person& p : persons) std::cout << p;
    }
    else
        std::cerr << "\n\n*** Error: Could not open source file\n";
    return 0;
}