[英]Difficulty reading from a file
我有一個包含逗號分隔值的文件
M,21,Hazel
F,49,Stephen
我將 ifstream 發送到一個 function 中,它接受 istream 來讀取該行。
ifstream file(fileName);
char gender;
file.get(gender);
file.ignore(); // ignore comma
if (gender == 'M') {
Gender* tmp = new Male;
file >> *tmp;
} else if (gender == 'F') {
Gender* tmp = new Female;
file >> *tmp;
}
逗號之前的第一個字符被正確讀取,但是當我發送它來閱讀時,它會在不需要時要求用戶輸入。 它不讀取文件的 rest 即“49,斯蒂芬”
istream& operator>>(istream& istr, ReadW& ref) {
return ref.read(istr);
}
istream& read(istream& is) {
char tName[16];
is >> age;
is.ignore(); // ignore comma
is.getline(tName, 16, ',');
}
基本上,您是在詢問有關讀取 csv 文件並將其拆分為令牌的信息。 如果你在 SO 上搜索這個,你會發現很多解釋如何做的帖子。
但就您而言,它可能更簡單。 如果保證源文件的格式完全符合上述格式,逗號前后沒有額外的空格,那么您可以使用流的標准提取器機制。 您只需將逗號讀入虛擬變量即可。 這可能看起來像:
// What we want to read
char gender{};
unsigned int age{};
std::string name{};
// This is a dummy
char comma{};
while (testDataStream >> gender >> comma >> age >> comma >> name) {
這將讀取變量gender
中的第一個字符,然后讀取逗號並將其放入comma
變量中。 我們根本不會使用這個。 然后,我們將繼續以相同的方式提取更多的值。
如果源文件的結構不同,它將不起作用。 例如,如果第一個變量是std::string
,那么testDataStream >> someString
將讀取完整行直到下一個空格。 但是,在現有結構下它會起作用。
無論如何,您還可以使用不同的功能,在輸入行格式錯誤的情況下,它會為您提供更多的安全性。 也就是說,首先讀取完整的一行,然后將其放入std::istringstream
並從中提取數據。
如果你有完全不同的數據結構,那么你可能會使用帶有分隔符的std::getline
或std::regex_token_iterator
的方法。 但這對這里來說就太多了。
此外,您顯然有一個 class 層次結構。 並且您根據運行時讀取的值創建派生類。 這通常用抽象工廠模式來解決。
我創建了一個可行的示例,您可以在其中看到所有這些機制。 請注意:我不會將 Plain C-Style char
arrays 用於字符串。 而且,我永遠不會對擁有的 memory 使用原始指針。為此,應該使用智能指針。
#include <iostream>
#include <sstream>
#include <memory>
#include <map>
#include <functional>
std::istringstream testDataStream(R"(F,21,Hazel
M,49,Stephen)");
// Abstract base class "Person"
struct Person {
// Constructor
Person(const unsigned int a, const std::string& n) : age(a), name(n) {}
// Do not forget the virtual destructor
virtual ~Person() { std::cout << "Destructor Base\n\n\n"; }
// The data: name and age
unsigned int age{};
std::string name{};
// Since the inserter is not none member function, we will write
// a separate virtual function to do the job polymorph
virtual std::ostream& output(std::ostream& os) const = 0;
// Inserter, will call our internal output function
friend std::ostream& operator << (std::ostream& os, const Person& p) {
return p.output(os);
}
};
// Derived class for a male Person
struct Male : public Person {
// Constructor
Male(const unsigned int age, const std::string& name) : Person(age, name) {}
virtual ~Male() { std::cout << "Destructor Male\n"; }
// And output
virtual std::ostream& output(std::ostream& os) const override {
return os << "Male Person:\nAge:\t" << age << "\nName:\t" << name << '\n';
}
};
// Derived class for a female Person
struct Female : public Person {
// Constructor
Female(const unsigned int age, const std::string& name) : Person(age, name) {}
virtual ~Female() { std::cout << "Destructor Female\n"; }
// And output
virtual std::ostream& output(std::ostream& os) const override {
return os << "Female Person:\nAge:\t" << age << "\nName:\t" << name << '\n';
}
};
// "Creation" Functions for abstract factory
std::unique_ptr<Person> createMale(const unsigned int age, const std::string& name) { return std::make_unique<Male>(age, name); }
std::unique_ptr<Person> createFemale(const unsigned int age, const std::string& name) { return std::make_unique<Female>(age, name); }
// Abstract factory
struct AbstractFactory {
// Abbreviation for finding
using Map = std::map<char, std::function<std::unique_ptr<Person>(const unsigned int, const std::string&)>>;
Map creationFunctions{
{'F', createFemale },
{'M', createMale }
};
std::unique_ptr<Person> create(const char selector, const unsigned int age, const std::string& name) {
// If the selector is in the map
if (Map::iterator searchResult{ creationFunctions.find(selector) }; searchResult != creationFunctions.end())
// Then we call the corresponding creation function
return creationFunctions[selector](age, name);
else
// No key found, the return nullptr (Empty Person());
return std::unique_ptr<Person>();
}
};
// Our abstract factor
AbstractFactory abstractFactory{};
// Driver code
int main() {
// What we want to read
char gender{};
unsigned int age{};
std::string name{};
// This is a dummy
char comma{};
std::string line{};
//#define DIRECT_READ
#ifdef DIRECT_READ
// As long as there is data in the stream, read the gender and the comma
while (testDataStream >> gender >> comma >> age >> comma >> name) {
#else
while (std::getline(testDataStream, line)) {
std::istringstream iss{ line };
if (iss >> gender >> comma >> age >> comma >> name) {
#endif
// Create a Person, either male or female
std::unique_ptr<Person> person = abstractFactory.create(gender, age, name);
// Polymorphism. Call the adequate member function
std::cout << *person << '\n';
// Do other stuff
// . . .
}
#ifndef DIRECT_READ
}
#endif
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.