c++ - 将 .txt 文件读入结构数组
问题描述
我是编程初学者,我正在尝试将我的 .txt 文件读入该程序中的结构数组,然后显示数据然后对其进行排序,但程序只读取第一行并且循环不会t 停止直到数组大小。文件数据如下所示:
ID NAME ADDRESS AGE
编码:
#include <iostream>
#include <fstream>
#include <string>
#include <conio.h>
using namespace std;
struct bio
{
char name[50], address[50];
int id, age;
};
int main()
{
int i = 0, arraysize = 1000;
bio b[arraysize];
fstream data;
data.open("biodata.txt");
while(data.read((char*)&b, sizeof(b[i])))
{
for (i = 1; i < 1000; i++)
{
data >> b[i].id >> b[i].name >> b[i].address >> b[i].age;
}
}
for (i = 0; i < 1000; i++)
{
cout << b[i].id << " " << b[i].name << " " << b[i].address << " " << b[i].age << " " << endl;
}
data.close();
getch();
}
解决方案
下面的内容对于初学者来说可能有点复杂,但是既然我们在谈论 C++,我们也应该寻找一种“更”面向目标的方法。
你设计了一个类,叫做 bio。在面向对象的语言中,您将把对象的所有数据以及对这些数据进行操作的所有函数都放在类中。所以你需要添加成员函数。这个想法是将所有数据封装在一个对象中。外界应该对上课的细节一无所知。您只需通过成员函数访问它。如果您想稍后进行更改,您将在类的成员函数中执行此操作。该程序的其余部分将继续工作。
此外,我们绝对应该使用 C++ 语言功能。例如,您应该使用std::string
字符串而不是普通的旧 C 样式字符数组。您基本上不应该在 C++ 中使用 C 样式数组。相反,请使用 STL 容器。
那么,让我们设计一个具有数据成员和成员函数的类。由于目前我们只需要输入和输出功能,因此我们覆盖了插入器和提取器操作符。这些操作员知道类的数据和行为,并会小心。
请参阅以下程序:
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
#include <sstream>
struct Bio
{
// Data
unsigned int id{};
std::string name{};
std::string address{};
unsigned int age{};
// Overload extractor operator to read all data
friend std::istream& operator >> (std::istream& is, Bio& b) {
std::string textLine{};
if (std::getline(is, textLine)) {
std::istringstream textLineStream{textLine};
textLineStream >> b.id >> b.name >> b.address >> b.age;
}
return is;
}
// Overload inserter operator to print the data
friend std::ostream& operator << (std::ostream& os, const Bio& b) {
return os << b.id << " " << b.name << " " << b.address << " " << b.age;
}
};
std::istringstream sourceFile{R"(1 John Address1 31
2 Paul Address2 32
3 Ringo Address3 33
4 George Address4 34
)"};
int main()
{
// Define Variable and read complete source file
std::vector<Bio> bio{std::istream_iterator<Bio>(sourceFile), std::istream_iterator<Bio>()};
// Sort the guys by name
std::sort(bio.begin(), bio.end(), [](const Bio& b1, const Bio& b2){ return b1.name < b2.name;});
// Show output on screen
std::copy(bio.begin(),bio.end(),std::ostream_iterator<Bio>(std::cout, "\n"));
return 0;
}
一些评论。在 StackOverflow 上,我无法使用文件。所以在我的示例程序中,我使用 astd::istringstream
代替。但这也是一个std::istream
。你也可以使用任何其他std::istream
的。所以如果你定义了一个```std::ifstream to read from a file, then it will work in the same way as the
std::istringstream````。
请看。提取器操作符完成读取源文件的全部工作。它是封装的。没有外部功能需要知道它是如何工作的。
在 main 函数中,我们定义 astd::vector
并使用它的范围构造函数来指定数据的来源。我们给它std::istream_iterator
,它遍历输入数据并调用提取器操作符,直到读取所有内容。
然后我们按名称排序并将结果复制到输出。
您可能会注意到输入数据中的字段以空格分隔。这通常不适用于非原子数据。名称可以由两部分组成,地址可以包含街道和城市。为此,发明了 CSV(逗号分隔值)文件。
请在下面查看更现实的灵魂。
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
#include <sstream>
#include <regex>
struct Bio
{
// Data
unsigned int id{};
std::string name{};
std::string address{};
unsigned int age{};
// Overload extractor operator to read all data
friend std::istream& operator >> (std::istream& is, Bio& b) {
std::string line{};
std::regex re{";"};
if (std::getline(is, line)) {
std::vector<std::string> token{std::sregex_token_iterator(line.begin(), line.end(), re, -1), std::sregex_token_iterator()};
if (4 == token.size()) {
b.id = std::stoul(token[0]);
b.name = token[1];
b.address = token[2];
b.age = std::stoul(token[3]);
}
}
return is;
}
// Overload inserter operator to print the data
friend std::ostream& operator << (std::ostream& os, const Bio& b) {
return os << b.id << ", " << b.name << ", " << b.address << ", " << b.age;
}
};
std::istringstream sourceFile{R"(1; John Lenon; Street1 City1; 31
2; Paul McCartney; Street2 City2; 32
3; Ringo Starr; Street3 City3; 33
4; George Harrison; Address4; 34
)"};
int main()
{
// Define Variable and read complete source file
std::vector<Bio> bio{std::istream_iterator<Bio>(sourceFile), std::istream_iterator<Bio>()};
// Sort the guys by name
std::sort(bio.begin(), bio.end(), [](const Bio& b1, const Bio& b2){ return b1.name < b2.name;});
// Show output on screen
std::copy(bio.begin(),bio.end(),std::ostream_iterator<Bio>(std::cout, "\n"));
return 0;
}
我们有一个新的源格式,主要是不变的。只是提取器运算符被修改。在这里,我们使用不同的迭代器来获取源数据。
推荐阅读
- python-3.x - Python3:尝试导入 nltk 时找不到“vcomp140.dll(或其依赖项之一)”
- ellipse - 如何在(水平定位的)椭圆周围分布 12 个点?
- python - python嵌套for循环通过第一个循环添加增量值
- javascript - 未找到模块:错误:您尝试导入位于项目 src/ 目录之外的 babel-preset
- python - 新值被复制到整列
- python - 检查 CSV 数据中的整数,然后删除该整数
- r - step_BoxCox() 带负数据
- c# - 我可以在 2 个不同的会话中调试 MVC 5 应用程序吗?
- spring - 弹簧延迟响应和路由器功能
- excel - Excel:是否可以在一页上运行两列列表并将其转移到辅助选项卡?