通过覆盖文件"Updating"文件中的行
"Updating" a line in a file by overwriting it
我正在尝试编写一个函数,该函数在调用时将搜索我的文本文件以查找与参数的匹配项,然后通过覆盖文件来"更新"它。
这是我目前的函数:
编辑:这是新更新的代码,仍然无法正常工作:/
以下是它发送到 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正确指出的那样,在第二个循环中,您从"GEM.txt"开始阅读,从您在第一个循环中已经遇到feof
开始。因此,您的第二个循环永远不会进入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 行,则使用向量会更安全,而不是使用数组。而且,您将不再需要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
标志添加到您的公开呼叫中。
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
- .cpp和.h文件中的模板专用化声明
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 文本文件中的单词链表
- CMake-按正确顺序将项目与C运行时对象文件链接
- 使用新行和不使用新行读取文件
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 挂起和取消挂起一个文件DLL
- 如何确定我已使用非编码文件到达 EOF?
- 命名空间中具有.h和.cpp文件的类
- 如何使用ndk-build.cmd构建Android.so文件
- 从包含m行的文件中提取n行,必要时(惰性地)重复该文件
- 读取文件并输入到矢量中
- 在C++中查找文件
- c++库的公共头文件中应该包含什么
- 用c++从输入文件中读取另一行
- Cppcheck生成xml转储文件
- 读取文件的最后一行并输入到链接列表时出错
- 无法编译 rtmidi 测试 cmidiin.cpp 文件, 非法指令
- 如何将内容数组写入文本文件?
- 通过覆盖文件"Updating"文件中的行