从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;
}
我有一个人 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;
}