[英]Read in objects from file in cpp
我有一個人 class 和一個寵物 class。 人有名字和年齡。 寵物有動物和它的顏色
人 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 是條目完成的“標志”
我不知道如何解釋每個人的寵物數量的變化,更不用說如何在 -1 處停止
這是我到目前為止的代碼:(適用於線性/沒有寵物數量變化的數據文件)
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 提取器運算符從 stream 中獲取所有數據。 對於寵物 class,我們將首先閱讀完整的行,包括動物和顏色。 為此,我們將使用最常用的std::getline
。
我們總是先閱讀完整的行,以避免行尾出現問題。 然后我們將剛剛讀取的行填充到std::istringstream
中。 這也是一個 stream,這樣,我們可以像從任何其他 stream 一樣從字符串中讀取。
從 stream 我們簡單地提取名稱和年齡。 沒那么復雜。
讀一個人有點復雜。 文件中的新條目可以以空行開頭。 所以我們將首先讀取空行並丟棄它們。
然后,我們再次將該行放入std::istringstream
,然后提取名稱和年齡。 簡單的。
接下來,可能有一個或多個寵物。 分隔符是包含 -1 的行。 因此,我們在 while 循環中讀取行,直到該行為 -1。 在 -1 的情況下,我們不會執行循環體。
如果它不是 -1,而是有效數據,我們再次將該行放入std::istringstream
並從該 stream 中提取一個 Pet。 線Pet pTemp; iss2 >> pTemp;
Pet pTemp; iss2 >> pTemp;
將致電寵物提取器操作員。 然后我們將新寵物添加到我們內部的std::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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.