我正在尝试创建一个待办事项列表程序。
我在从txt文件中删除任务时遇到问题,我尝试从程序中读取所有数据并将某些数据替换为空白,但最终仍然留下了一些字符。
bool DoList::Remove_Task()
{
std::ofstream temp_file("temp.txt", std::ios::app);
std::ifstream file("Tasks_Data.txt");
if (!temp_file.is_open())
{
std::cerr << "temp File cannot be opened to modify";
return false;
}
else if (!file.is_open())
{
std::cerr << "File cannot be opened to read";
return false;
}
else
{
int ID;
int search;
std::string TaskName;
std::string Description;
std::string Status;
char str[26];
std::string line;
std::cout << "Enter Your Task ID to remove: ";
std::cin >> search;
while (getline(file, line))
{
while(file >> ID)
if (ID == search)
{
ID = 0;
TaskName = "\0";
Description = "\0";
Status = "\0";
strcpy_s(str, "\0");
temp_file << ID << ". " << std::setprecision(5) << TaskName << ", " << std::setprecision(5) << Description << ", " << std::setprecision(5) << Status << ", " << std::setprecision(5) << str << std::endl;
}
else
{
temp_file << line;
}
}
}
file.close();
temp_file.close();
remove("Tasks_Data.txt");
rename("temp.txt", "Tasks_Data.txt");
return true;
}
原代码:
std::ofstream temp_file("temp.txt", std::ios::app);
文件已打开以进行追加。如果先前的实例崩溃,文件将包含先前运行的数据。只需打开它即可写入。
原代码:
while (getline(file, line))
{
while(file >> ID)
您已经读完了整行。
file >> ID
将从下一行读取ID。解析 line
以确定其 id。例如,您可以使用 std::stringstream:
int task_id;
std::stringstream(line) >> task_id;
原代码:
temp_file << ID << ". " << std::setprecision(5) << TaskName << ", " << std::setprecision(5) << Description << ", " << std::setprecision(5) << Status << ", " << std::setprecision(5) << str << std::endl;
对于不删除的行,您不需要解析它们并生成新的行。只需写下整行:
temp_file << line << std::endl;
原代码:
return false;
}
else if (
如果前一个块从函数返回,则不需要
else
部分。
原代码:
remove("Tasks_Data.txt");
rename("temp.txt", "Tasks_Data.txt");
您不需要删除旧文件。
rename()
将原子地用新的替换它。
整个函数可能是这样的(
id
删除作为参数传递的参数,不检查格式错误):
bool Remove_Task(int id)
{
std::ofstream temp_file("temp.txt");
if (!temp_file.is_open()) {
std::cerr << "temp File cannot be opened to modify";
return false;
}
std::ifstream file("Tasks_Data.txt");
if (!file.is_open()) {
std::cerr << "File cannot be opened to read";
return false;
}
std::string line;
while (getline(file, line))
{
int task_id;
std::stringstream(line) >> task_id;
if (task_id != id) {
temp_file << line << std::endl;
}
}
file.close();
temp_file.close();
rename("temp.txt", "Tasks_Data.txt");
return true;
}
将您的问题分解为任务,将用户体验(读取和写入控制台)与访问数据(读取和写入文件)分开。
您需要的核心。该函数接受“行”(字符串)列表并删除具有指定任务 ID 的字符串。这个函数的神奇之处在于它只关心解析“行”,并找到行开头的前导数字。
bool RemoveTaskFromList(int taskIdToRemove, std::vector<std::string>& lines)
{
bool found = false;
for (auto itor = lines.begin(); itor != lines.end();)
{
std::string line = *itor;
std::istringstream ss(line);
int id;
ss >> id;
if (id == taskIdToRemove)
{
found = true;
itor = lines.erase(itor); // returns a new iterator to "one past" what was just erased
}
else
{
itor++;
}
}
return found;
}
请注意,上述函数不必将整行解析为组成部分。它只需要“读取”行开头的前导数字。它不是最强大的。如果该行不以数字开头,则
id
将被分配为零。您可以根据需要更改此设置。
另一个对文件执行实际 I/O 的函数(读取和写入磁盘)。它不需要了解有关各行格式的架构的任何信息。它只需要将所有行作为单独的字符串读取到字符串向量中。
bool RemoveTaskFromFile(int taskIdToRemove, const std::string& fileName, bool& ioError)
{
std::ifstream ifile(fileName);
ioError = false;
if (!ifile)
{
ioError = true;
return false;
}
// read all the lines
std::vector<std::string> lines;
std::string line;
while(std::getline(ifile, line))
{
lines.push_back(line);
}
ifile.close();
// remove the line
bool found = RemoveTaskFromList(taskIdToRemove, lines);
if (found == false)
{
return false;
}
// open the file again for writing
std::ofstream ofile(fileName);
if (!ofile)
{
ioError = true;
return false;
}
// write all the lines back that were not removed from the vector
for (const auto& line : lines)
{
ofile << line << "\n";
}
return true;
}
第三个与用户实际互动的功能:
bool DoRemove()
{
int id;
std::cout << "task id to remove\n";
std::cin >> id;
bool ioError;
bool wasRemoved = RemoveTaskFromFile(id, "Tasks_Data.txt", ioError);
if (ioError)
{
std::cout << "error reading or writing file\n";
}
else if (!wasRemoved)
{
std::cout << "can't find task in file\n";
}
else
{
std::cout << "successfully removed\n";
}
return wasRemoved;
}
这是一个练习,让您将其融入到
DoList
课程中。