C++文件IO实现按序号删除待办事项整行功能求助
解决C++待办事项列表的行删除问题
嘿,我明白你现在的困扰——用临时文件删行要么错删要么只删序号,这大概率是你的del函数逻辑没处理好行匹配和文件读写的细节。我来帮你把这个功能搞定,先看完整的修正代码,再给你拆解关键步骤。
首先,补上你没写完的add、view函数,同时重点修正del函数:
#include <iostream> #include <iomanip> #include <string> #include <fstream> #include <stdlib.h> #include <algorithm> using namespace std; // Class for our add, delete, and view functions. class Todo { public: void add(string item); void del(string item); void view(); private: // 辅助函数:修剪字符串前后的空白字符 string trim(const string& s) { auto start = s.begin(); while (start != s.end() && isspace(*start)) { start++; } auto end = s.end(); do { end--; } while (distance(start, end) > 0 && isspace(*end)); return string(start, end + 1); } }; int main () { Todo l; string item; char command; lPlaceholder: cout << "\t\tYour ToDo List" << endl; cout << "Press + then enter your item to add to the list" << endl; cout << "Press - then enter your items serial number to remove" << endl; cout << "Press ? to display all items in your list" << endl; cout << "Press x to quit the program" << endl; cin >> command; if (command == '+' || command == '-') { getline(cin, item); } // Simple menu switch(command){ case '+': l.add(item); goto lPlaceholder; case '-': l.del(item); goto lPlaceholder; case '?': l.view(); goto lPlaceholder; case 'x': exit (0); default: cout << "Invalid choice.\n"; goto lPlaceholder; } } // Add function void Todo::add(string item) { // 先获取当前已有任务的数量,用来生成序号 int count = 0; ifstream inFile("todo.txt"); string line; while (getline(inFile, line)) { count++; } inFile.close(); // 写入新任务,格式为 "序号. 任务内容" ofstream outFile("todo.txt", ios::app); if (outFile.is_open()) { outFile << count + 1 << ". " << trim(item) << endl; cout << "Task added successfully!\n"; outFile.close(); } else { cout << "Error opening file to add task.\n"; } } // Delete function void Todo::del(string item) { // 1. 解析用户输入的序号:先修剪空白,转成整数 string numStr = trim(item); int targetLine; try { targetLine = stoi(numStr); } catch (...) { cout << "Invalid serial number! Please enter a number.\n"; return; } // 2. 打开原文件和临时文件 ifstream inFile("todo.txt"); ofstream tempFile("temp.txt"); if (!inFile.is_open() || !tempFile.is_open()) { cout << "Error opening files for deletion.\n"; return; } // 3. 逐行读取,跳过目标行,写入临时文件并重新生成序号 string line; int currentLine = 0; bool found = false; while (getline(inFile, line)) { currentLine++; if (currentLine != targetLine) { // 删除目标行后,后续行的序号要递减 int newNum = currentLine - (found ? 1 : 0); // 提取原行的任务内容,重新拼接带新序号的行 size_t dotPos = line.find(". "); if (dotPos != string::npos) { tempFile << newNum << ". " << line.substr(dotPos + 2) << endl; } } else { found = true; cout << "Task " << targetLine << " deleted successfully!\n"; } } // 4. 关闭文件 inFile.close(); tempFile.close(); // 5. 处理没找到目标行的情况 if (!found) { cout << "No task found with serial number " << targetLine << ".\n"; remove("temp.txt"); // 删除空的临时文件 return; } // 6. 替换原文件 remove("todo.txt"); rename("temp.txt", "todo.txt"); } // View function void Todo::view() { ifstream inFile("todo.txt"); if (!inFile.is_open()) { cout << "Your todo list is empty!\n"; return; } string line; cout << "\nYour ToDo Items:\n"; while (getline(inFile, line)) { cout << line << endl; } inFile.close(); }
关键修正点解释:
输入解析与验证:
- 新增
trim辅助函数,清理用户输入里的多余空白(比如输入- 2时,item是" 2",trim后变成"2")。 - 用
stoi转换序号并捕获异常,避免非数字输入导致程序崩溃。
- 新增
删除后重新生成序号:
这是你最可能踩坑的地方!如果只是跳过目标行,后续行的序号会断层(比如删了第2行,第3行还是显示3)。写入临时文件时,我们会重新计算每一行的序号:找到目标行后,后续行的序号自动减1,保持列表序号连续。完整的错误处理:
增加了文件打开失败的判断,以及目标序号不存在时的提示,避免无效的文件替换操作。菜单逻辑补全:
在default分支加了goto lPlaceholder,避免输入无效命令后直接退出程序。
现在测试一下:输入- 2,程序会精准找到第2行并跳过它,同时将后面的任务重新编号写入临时文件,最后替换原文件,完美实现删除指定序号的整行任务。
内容的提问来源于stack exchange,提问作者Spazzdazz
相关产品推荐
相关产品推荐

