我有一个文件,其中包含该学生的学生姓名、ID、年龄和编号。我想读取文件,例如,如果学生人数为 2,则删除与该学生对应的所有 3 个先例行。
我的txt是这样的
<块引用>马克
45646564
18
1
让
4563213
21
2
保罗
45654
22
4
爱丽丝
45948
20
5
while (getline(student, line))
{
if (counter % 4 == 2) { // Here I want to delete all prcedent 3 lines}
}
答案 0 :(得分:0)
不幸的是,您的方法或您的设计理念不是很好。应该稍微改进一下。
您需要开始以面向对象的方式思考。对象“student”具有属性或数据元素,例如“name”、“id”、“age”和“number”。所有这些数据都属于一起,并与特定的“学生”相关。接下来,您需要定义应该对这些数据进行操作的方法,例如“读取”和“写入”某些学生的完整数据。
如果您在阅读完整的“学生”记录后拥有的“数字”属性没问题,那么您将其存储在某种数组中或std::vector
那么,让我们从数据部分开始:
struct Student {
std::string name{};
unsigned long id{};
unsigned int age{};
unsigned int number{};
};
这将描述一名学生的属性。
接下来,我们确实想对这些数据进行操作。第一个操作是我们确实希望从任何类型的 stream
读取这些数据,例如从控制台 (std::cin
) 或从文件 (std::ifstream
)。这基本上无关紧要,流就是流:-)
iostream 库具有所谓的“提取器”操作符,用于从流中读取数据。那是 >>
运算符。这我们可以简单地为我们的“学生”结构定义。像这样:
friend std::istream& operator >> (std::istream& is, Student& s) {
return std::getline(is >> std::ws, s.name) >> s.id >> s.age >> s.number;
}
给出了函数的签名。这是正式的要求。然后,现在我们在该函数中做什么。我想提醒大家,istream
提取操作总是返回对给定 istream.
的引用。所以,首先我们调用 std::getline
。这将读取学生的姓名,然后再次返回。然后该行看起来像 return is >> s.id >> s.age >> s.number
。接下来我们将读取 id。这也将返回。然后语句看起来像 return is >> s.age >> s.number
。等等等等。最后,我们将阅读所有内容,只需return is;
在 std::getline
中,您将看到 >>std::ws
。这将忽略所有前导空格,如换行符或其他任何内容。
所以,现在,如果我们有一个打开的文件流,比如说“ifs”和一个名为“student”的学生变量,那么我们可以写ifs >> student
,它会从文件中读取一个完整的学生记录文件。所以,所有 4 行。
顺便说一下,我们可以对插入函数 <<
做同样的机制。
如果我们现在循环运行并将读取的学生数据存储到 std::vector
中,我们可以从文件中复制所有数据。
或者,如果一个学生有某个属性,那么我们也可以决定不复制数据。
这可能看起来像:
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
struct Student {
std::string name{};
unsigned long id{};
unsigned int age{};
unsigned int number{};
friend std::istream& operator >> (std::istream& is, Student& s) {
return std::getline(is >> std::ws, s.name) >> s.id >> s.age >> s.number;
}
friend std::ostream& operator << (std::ostream& os, const Student& s) {
return os << s.name << '\n' << s.id << '\n' << s.age << '\n' << s.number << '\n';
}
};
int main() {
// Here we will store all our studends
std::vector<Student> students{};
// Open the file with the data
std::ifstream ifs("r:\\data.txt");
// Check, if the file could be opened.
if (ifs) {
Student tempStudent{};
// Read all students from a file, until we hit eof or some other problem
while (ifs >> tempStudent) {
// if the student does fullfill the requirements, then we take it, else not
if (tempStudent.number != 2)
students.emplace_back(std::move(tempStudent));
}
// OK, for debug purposes we show all data ion the screen
for (const Student& s : students) std::cout << s << '\n';
}
else std::cerr << "\n\nError: source file could not be opened\n\n";
return 0;
}
如果您想查看更高级的 C++ 解决方案,请查看以下内容:
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <iterator>
#include <algorithm>
struct Student {
std::string name{};
unsigned long id{};
unsigned int age{};
unsigned int number{};
friend std::istream& operator >> (std::istream& is, Student& s) {
return std::getline(is >> std::ws, s.name) >> s.id >> s.age >> s.number;
}
friend std::ostream& operator << (std::ostream& os, const Student& s) {
return os << s.name << '\n' << s.id << '\n' << s.age << '\n' << s.number << '\n';
}
};
int main() {
// Here we will store all our studends
std::vector<Student> students{};
// Open the file with the data and check, if it is open
if (std::ifstream ifs("r:\\data.txt");ifs) {
// Read all data
std::copy_if(std::istream_iterator<Student>(ifs), {}, std::back_inserter(students), [](const Student& s) {return s.number != 2;});
// For debug purposes we show all data ion the screen
std::copy(students.begin(), students.end(), std::ostream_iterator<Student>(std::cout, "\n"));
}
else std::cerr << "\n\nError: source file could not be opened\n\n";
return 0;
}