从文本文件读取,然后将项目存储到列表中

Reading from text file and then store the item into a list

本文关键字:存储 项目 列表 然后 文本 文件 读取      更新时间:2023-10-16

Im 试图读取名为stock.txt的文件,该文件包含以下值:

ID、项目、颜色、尺寸、数量、价格

11,T-shirt,blue,XL,2,10.500000
12,Supreme,red,M,10,20.500000
13,BANG,red,M,10,20.500000

我想将每个项目存储在列表中,我该怎么做?

int main() {
ifstream infile;
infile.open("Stock.txt");
string id; string title; string colour; string size; string quantity; string cost;
//If file open is successful
while(infile.good()){
getline(infile,id,',');
getline(infile,title,',');
getline(infile,colour,',');
getline(infile,size,',');
getline(infile,quantity,',');
getline(infile,cost,'n');        
}
infile.close();
}

您应该使用更现代的C++方法。

如果您可以研究此解决方案并尝试将来使用某些功能,我将很高兴。

在面向对象的世界中,我们使用类(或结构(,并将数据和函数放在一个(封装的(对象中,对这些数据进行操作。

只有类应该知道如何读取和写入其数据。不是一些外部全局函数。因此,我在您的结构中添加了 2 个成员函数。我已经覆盖了机械臂和提取器运算符。

在提取器中,我们将使用现代C++算法,将字符串拆分为标记。为此,我们有std::sregex_token_iterator.而且因为有一个专门的功能用于此目的,我们应该使用它。此外,它非常简单。

使用下面的单行代码,我们将整个字符串拆分为标记,并将生成的标记放在std::vector

std::vector token(std::sregex_token_iterator(line.begin(), line.end(), delimiter, -1), {});

然后,我们将结果数据复制到成员变量中。

对于演示输出,我还覆盖了机械臂操作员。现在,您可以将外部操作器和机械臂运算符(">>"和"<<"(用于 Stock 类型的变量,就像任何其他C++整变量一样。

总的来说,我们也使用一种超简单的方法。首先,我们打开文件并检查这是否正常。

然后我们定义一个变量"stocks"(Astd::vectorof Stocks(,并使用其范围构造函数和std::istream_operator来读取完整的文件。而且,由于该应用程序具有覆盖的提取器运算符,因此它知道如何读取并将为我们解析完整的CSV文件。

再次,非常简单和简短的单行

std::vector stocks(std::istream_iterator<Stock>(inFile), {});

将读取完整的源文件、所有行,解析行并将成员变量存储在生成的std::vector的单个库存元素中。

#include <string>
#include <iostream>
#include <vector>
#include <fstream>
#include <regex>
#include <iterator>
#include <algorithm>

std::regex delimiter{ "," };
struct Stock {
// The data. Member variables
std::string id{};
std::string title{};
std::string colour{};
std::string size{};
std::string quantity{};
std::string cost{};
// Overwrite extractor operator
friend std::istream& operator >> (std::istream& is, Stock& s) {
// Read a complete line
if (std::string line{}; std::getline(is, line)) {
// Tokenize it
std::vector token(std::sregex_token_iterator(line.begin(), line.end(), delimiter, -1), {});
// If we read at least 6 tokens then assign the values to our struct
if (6U <= token.size()) {
// Now copy the data from the vector to our members
s.id = token[0];
s.title = token[1];
s.colour = token[2];
s.size = token[3];
s.quantity = token[4];
s.cost = token[5];
}
}
return is;
}
// Overwrite inserter operator
friend std::ostream& operator << (std::ostream& os, const Stock& s) {
return os << "ID: " << s.id << "nTitle: " << s.colour
<< "nSize:   " << s.size << "nQuantity:  " << s.quantity << "nCost: " << s.cost;
}
};
int main() {
// Open file and check, if it could be opened
if (std::ifstream inFile("stock.txt"); inFile) {
// Define the variable and use range constructor to read and parse the complete file
std::vector stocks(std::istream_iterator<Stock>(inFile), {});
// Show result to the user
std::copy(stocks.begin(), stocks.end(), std::ostream_iterator<Stock>(std::cout, "n"));
}
return 0;
}

请注意:我使用的是 C++17,可以在没有模板参数的情况下定义 std::vector。编译器可以从给定的函数参数推断参数。此功能称为 CTAD("类模板参数推导"(。

此外,您可以看到我没有明确使用"end(("迭代器。

此迭代器将从具有正确类型的空大括号括起来的初始值设定项列表构造,因为由于 std::vector 构造函数需要它,它将被推导出为与第一个参数的类型相同。

您应该使用classstruct对每一行进行建模:

struct Record
{
int id;
std::string title;
std::string colour;
std::string size;
int quantity;
double price;
friend std::istream& operator>>(std::istream& input, Record & r);
};
std::istream& operator>>(std::istream& input, Record & r)
{
char comma;
input >> r.id;
input >> comma;
std::getline(input, r.title, ',');
std::getline(input, r.colour, ',');
std::getline(input, r.size, ',');
input >> r.quantity;
input >> comma;
input >> r.price;
input.ignore(100000, 'n');
return input;
}

现在您可以读入列表:

std::list<Record> database;
Record r;
while (infile >> r)
{
database.push_back(r);
}

operator>>的重载使代码更简单、更易于阅读。