我正在尝试编写一个函数,该函数在被调用时会在我的文本文件中搜索与参数匹配的内容,然后通过覆盖文件来“更新”它。
这是我当前的功能:
编辑:这是新的更新代码,仍然无法正常工作:/
这是它发送给 UpdateGem 的行:(示例 sTempTxt:“AB:5.55”)
ostringstream stream;
stream << std::setprecision(3) << fEindgem;
string sTempTxt = sVak + ":" + stream.str() + "\n";
UpdateGem(sTempTxt);
void UpdateGem(string text)
{
ifstream f;
f.open("GEM.txt");
string sGEMS[100];
string temp[3];
splitstring(text, ":", temp[0], temp[1]);
bool OverWrite;
int count = 0;
string Delete, line;
while(true)
{
getline(f, sGEMS[count], '\n');
if(f.eof()) break;
splitstring(sGEMS[count], ":", temp[1], temp[2]);
if (temp[0] == temp[1])
{
OverWrite = 1;
Delete = sGEMS[count];
}
count++;
}
// Don't set count to 0, since we need it
// count = 0;
ofstream f2;
f2.open("GEM2.txt"/*,std::ios_base::app*/);
if (OverWrite)
{
f.seekg(0, std::ios::beg);
for (int i = 0; i < count; ++i)
{
if (sGEMS[i] != Delete) f2 << sGEMS[i];
}
}
f.close();
f2.close();
remove("GEM.txt");
rename("GEM2.txt", "GEM.txt");
ofstream file;
file.open("GEM.txt",std::ios_base::app);
file << text;
file.close();
}
它必须替换的行采用 NAME:NUMBER 的形式,其中数字可以不同,因此我使用 splitstring 函数将名称与找到的行的名称进行比较,然后完全删除该行并通过稍后重新添加来“更新”它。但是,我当前的代码只将更新的行写入文件,而不是旧的...
最佳答案
从您的程序看来,您假设“GEM.txt”中的文本永远不会超过 100 行。但是,在您对文件的初始扫描中,您不记得读入了多少行。因此,为了弥补这一点,您尝试通过重新读取原始“GEM.txt”文件来记住多少行,并将您保存的行写入“GEM2.txt”。
正如 jrok 正确指出的那样,在您的第二个循环中,您正在从您在第一个循环中遇到 feof
时开始读取“GEM.txt”。所以,你的第二个循环永远不会进入 while
循环,因为 getline
调用认为没有什么可以得到的(因为 f
在最后文件)。所以 jrok 给了你在第二个 while
循环之前添加的代码行:
f.seekg(0, std::ios::beg);
但是,由于您已经将所有行保存在一个数组中,因此您可以直接将 sGEMS
数组写入您的新文件中。
// Don't set count to 0, since we need it
// count = 0;
ofstream f2;
f2.open("GEM2.txt"/*,std::ios_base::app*/);
if (Overwrite) {
for (int i = 0; i < count; ++i) {
if (sGEMS[i] != Delete) f2 << sGEMS[i] << std::endl;
}
}
//...
如果文件超过 100 行,使用 vector 会比使用数组更安全。而且,您将不再需要 count
,因为它是根据 vector
的大小进行跟踪的。
std::vector<std::string> sGEMS;
//...
while (true) {
getline(f, line);
if (f.eof()) break;
sGEMS.push_back(line);
//...
}
如果您预计“GEM.txt”文件非常大,您可能需要重新考虑您处理该文件的方式。特别是,您应该只记住要跳过的行号,并将行从“GEM.txt”复制到“GEM2.txt”,就像您最初尝试做的那样。
最后,在最后编写的代码中,您打开文件进行追加,但不进行输出。 C++ 认为这意味着您想丢弃文件的内容。相反,将 ios_base::out
标志添加到您的 open 调用中。
ios_base::openmode mode = ios_base::out|ios_base::app;
file.open("GEM.txt",mode);
file << text << std::endl;
file.close();
但是,您可以在关闭它之前将它附加到 f2
的末尾,而不是那样做。
根据我的建议,UpdateGem
的最终形式应该是:
void UpdateGem(string text) {
ifstream f;
ofstream f2;
vector<string> sGEMS;
string temp[3];
bool OverWrite;
string Delete, line;
splitstring(text, ":", temp[0], temp[1]);
sGEMS.reserve(100);
f.open("GEM.txt");
while (true) {
getline(f, line);
if (f.eof()) break;
sGEMS.push_back(line);
splitstring(line, ":", temp[1], temp[2]);
if (temp[0] == temp[1]) {
OverWrite = 1;
Delete = line;
}
}
f.close();
f2.open("GEM2.txt"/*,std::ios_base::app*/);
if (OverWrite) {
for (int i = 0; i < sGEMS.size(); ++i) {
if (sGEMS[i] != Delete) f2 << sGEMS[i] << std::endl;
}
}
f2 << text << std::endl;
f2.close();
remove("GEM.txt");
rename("GEM2.txt", "GEM.txt");
}
我用下面的 main
程序测试了代码:
int main () { UpdateGem("Test:0001"); }
并像这样实现splitstring
:
bool splitstring (string s, string match, string &a, string &b)
{
int x = s.find(match);
if (x != string::npos) {
a = s.substr(0, x);
b = s.substr(x+match.size());
return true;
}
return false;
}
当输入以下输入“GEM.txt”时:
a:x
b:x
Test:1234
c:x
程序将“GEM.txt”的内容修改为:
a:x
b:x
c:x
Test:0001
关于c++ - "Updating"文件中的一行被覆盖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11074697/