在每一行中,都有一个字符串和一个数字。我已经完成搜索功能以搜索名称并且它可以正常工作
例如,在包含以下内容的文件中:
Batman 290
Joker 100
Spiderman 300
但我现在面临的问题是如何修改字符串旁边的数字。例如,当我搜索“蝙蝠侠”这个名字时,我只想改变蝙蝠侠的号码。
以下是添加代码:
void Teacher::addScore(string name, double score) {
outStream.open("StudentRecord.txt", ios_base::app);
outStream << name << " || " << score << endl;
outStream.close();
}
搜索
string Teacher::search(string searchKeyword) {
int count = 0;
string name;
readStream.open("StudentRecord.txt");
while (readStream.is_open()) {
getline(cin, name);
while (readStream >> name) {
if(name == searchKeyword) {
count++;
return name;
}
}
if(name != searchKeyword) {
return "That student doesnt exist";
}
}
return "";
}
为了修改,我在这个阶段遇到了麻烦
void Teacher::modifyScore() {
string name;
string searchResult;
cout << "You want to modify the a student score?" << endl;
cout << "Which student's you want to change?" << endl;
cin >> name;
searchResult = search(name);
outStream.open("StudentRecord.txt", ios::trunc);
// What should I do here to modify a student number?
}
答案 0 :(得分:2)
第二次编辑:使用读/写代码
请注意,代码不是最佳的,并且没有任何错误检查。假设数据位于“data.txt”中。
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
#include <map>
int main()
{
// Holds file data
std::map<std::string, int> data;
// Read file and fill data map
std::ifstream ifs("data.txt");
std::string line;
while (std::getline(ifs, line))
{
std::string name;
int number;
std::stringstream ss(line);
ss >> name >> number;
data[name] = number;
}
ifs.close();
// Print data
for (auto& entry : data)
{
std::cout << entry.first << " " << entry.second << std::endl;
}
// Modify data
data["Batman"] += 100;
// Open same file for output, overwrite existing data
std::ofstream ofs("data.txt");
for (auto& entry : data)
{
ofs << entry.first << " " << entry.second << std::endl;
}
ofs.close();
return 0;
}
编辑:原始答案假定文件结构已知(字符串和每行数)
要在文件中查找数字,您需要将文件内容解析为所谓的 “令牌”。 示例:字符串“foo 10 0.1”将使用空白字符作为分隔符分解为“foo”,“10”,“0.1”。此过程称为标记化。 接下来,您需要检查每个令牌是否代表有效数字,为此,只需检查每个字符是否为有效整数。
原创amswer:
您基本上需要执行以下操作
如果输入文件必须用作输出文件,只需重写打开标记(默认为afaik)
答案 1 :(得分:1)
我更改了代码以正确处理文件,您应该能够测试它:
#include "stdafx.h" // for VC++
#include <iostream>
#include <fstream>
#include <string>
#define score_file "d:\\StudentRecord.txt"
#define score_file_bak score_file".bak"
#define score_file_new score_file".new"
using namespace std;
void addScore(string name, double score)
{
ofstream outStream;
outStream.open(score_file, ios_base::app);
outStream << name << "||" << score << endl;
outStream.close();
}
void modifyScore(string name, double score) {
string line;
int fd =0;
ifstream scores(score_file);
if(!scores.is_open()){
std::cout << "Unable to read score file" << std::endl;
return ;
}
ofstream outStream(score_file_new);
if(!outStream.is_open()){
std::cout << "Unable to open temp file to write" << std::endl;
return ;
}
name += "||";
while(getline(scores, line)){
if(line.find(name) == 0){
std::cout << "Found: " << line << std::endl;
outStream << name << score << std::endl;
fd++;
}
else{
outStream << line << std::endl;
}
}
scores.close();
outStream.close();
if(fd<1){
remove(score_file_new);
std::cout << "Not found: " << name << std::endl;
}
else{
remove(score_file_bak);// delete previous backup
if(0 != rename(score_file,score_file_bak)){
std::cout << "Unable to backup" << std::endl;
remove(score_file_new); // delete the new file since update failed
return;
}
if(0 == rename(score_file_new,score_file))
std::cout << "Updated succeeded." << std::endl;
else
std::cout << "Unable to update\n" << std::endl;
}
}
void showScore()
{
string line;
ifstream scores(score_file);
while(getline(scores, line)){
cout << line << std::endl;
}
scores.close();
}
int main()
{
bool reset_scores = true; //do you want to reset all scores?
if(reset_scores) // clean all old records?
{
ofstream outStream(score_file, ios_base::trunc);outStream.close();
addScore("Tom",120); addScore("Jerry", 130); addScore("Tim",100);
}
std::cout << "Here are the scores" << std::endl;
showScore();
std::cout << "Try to change Timmy's score:" << std::endl;
modifyScore("Timmy",200);
showScore();
std::cout << "Try to change Jerry's score:" << std::endl;
modifyScore("Jerry",1190);
showScore();
if(1)
{
string aaa;
std::cout << "Press enter to quit:\n";
getline(cin, aaa);
}
return 0;
}
我有这个输出:
Here are the scores
Tom||120
Jerry||130
Tim||100
Try to change Timmy's score:
Not found: Timmy||
Tom||120
Jerry||130
Tim||100
Try to change Jerry's score:
Found: Jerry||130
Updated succeeded.
Tom||120
Jerry||1190
Tim||100
Press enter to quit:
您需要了解如何自己处理输入。
答案 2 :(得分:0)
你不能在他们的中间修改files“;也就是说,您只能截断或附加到文件,或者用另一个字节(相同长度)字节覆盖字节的子序列。
所以你可以按照RedAgito's anser的建议读取内存中的整个文件,修改内存中的表示,然后重写完整整个文件。
当然,这种方法不是很scalable(但实际上是值得的:笔记本电脑有几千兆字节的RAM,而一千兆字节的文本文件将包含数百万个名字 - 数字行,这通常足够了):单个修改的复杂性与行数成正比(除非你知道所有数字都是相同的宽度 - 例如一些电话号码;然后你可以覆盖该行,但你仍然需要找到那条匹配的行)
实用的方法可能是使用某个数据库(可能像sqlite库一样简单;或者像PostGreSQL或MongoDB这样的全功能DBMS,或者某些索引文件库(如GDBM或kyotocabinet)。
另一种方法可能是使用一些传统的文本结构化格式,如JSON或YAML(或者可能是XML,不太适合您的任务)。存在许多能够容易地处理这种格式的C ++库(例如jsoncpp和许多其他)。然后,您将解析完整文件(在几个C ++语句中),可能作为单个(但很大)的JSON对象,然后修改内存中的数据,然后再次写入。
如果您不能使用其中任何一项(例如,如果它是一些家庭作业,而您的老师正在限制您),您可能会编写自己的例程来管理固定大小的记录(并且可能在它们之上提供一些更高级别的抽象)是一些标记的联合可能包含其他记录的偏移量(这基本上是数据库系统和索引文件正在做的事情)。如果你被限制使用文本文件(这是一个好主意;你最好有你可以用任何好的编辑器修改的数据,àlaemacs
或vim
),那么你必须解析整个文件,将其表示存储在内存中(例如,在您的情况下可能是一些std::map<std::string,long>
,密钥是名称),然后重写整个文件。