以下代码尝试覆盖文件中的不同位置并附加到文件中。但是,它似乎不起作用。我已经尝试了几种模式,结果是覆盖或只是将所有内容附加到文件的末尾,但不是两者都在一起。是否有可能在C ++中做这样的事情?或者,我们是否需要在不同模式下一次又一次地打开文件才能完成此任务?
int main() {
fstream f("a.dat", ios::out | ios::app);
f.seekp(ios::beg);
f << "hello world";
f.seekp(ios::end);
f << "works";
return 0;
}
答案 0 :(得分:5)
您是否希望在文件中的某个位置插入数据?根据我的经验,至少有fstream
s没有插入。这很像在数组中写入数据。只需在数组的开头和结尾之间的某处指向并在那里写入就不会插入,它会覆盖。
处理它就像将数据插入数组的中间一样。您必须向前移动数据以为插入腾出空间。
计算插入所需的空间,并在插入缓冲区后读取所有数据,在将写入指针向前移动之后,将该缓冲区中的数据写回文件中您需要插入空间。然后,将写指针移回您想要插入的位置,并写入您计划插入的数据。
编辑: 请求的代码示例:
#include <fstream>
int main(int argc, char* argv[])
{
std::fstream FileStream;
// Initial write.
FileStream.open("Test.txt", std::ios::out | std::ios::trunc);
FileStream << "OLDDATAOLDDATA";
FileStream.close();
// Prepare data to insert.
const char InsertionData[] = "newdata";
const unsigned int InsertionDataLength = strlen(InsertionData);
// Insertion write.
FileStream.open("Test.txt", std::ios::in | std::ios::out | std::ios::ate);
std::ios::pos_type InsertionPosition = 7; // 7 is the start index of the second "OLDDATA".
FileStream.seekg(0, std::ios::end);
std::ios::pos_type EndPosition = FileStream.tellg();
// Read rest of file.
const unsigned int RestOfFileDataLength = EndPosition - InsertionPosition;
char* const RestOfFileData = new char[RestOfFileDataLength];
FileStream.seekg(InsertionPosition);
FileStream.read(RestOfFileData, RestOfFileDataLength);
// Rewrite rest of file.
FileStream.seekp(InsertionPosition);
FileStream.write(InsertionData, InsertionDataLength);
FileStream.write(RestOfFileData, RestOfFileDataLength);
delete[] RestOfFileData;
FileStream.close();
}
一些笔记。您插入的文件越早,它就越贵,因为您需要在它之后移动所有内容。这也意味着更大的文件插入更昂贵。如果你要进行多次插入,你可以尝试跟踪每个插入并推迟它们,直到调用某种flush命令,此时只需要对文件的其余部分进行1次主要的读/写操作,而不是每个插入调用一个。理想情况下,您应该将它包装在您自己的某种包装中。
答案 1 :(得分:4)
如果您在打开文件时指定ios::app
,则所有写入将始终到达文件末尾 - 基本上就好像每个写入前面都有f.seekp(ios::end)
听起来你想要的是ios::ate
。这将在文件打开后立即寻找文件的末尾,但是当/如果你寻找文件中的其他地方并写入时,写入将转到文件中的当前点而不是结束。
编辑3:我添加了代码以回到最后并在那里添加更多内容:
#include <fstream>
#include <iostream>
int main() {
std::fstream f("test.txt", std::ios::in | std::ios::out | std::ios_base::ate);
f << " added to end.";
f.seekp(0, std::ios::beg);
f << "Original";
f.seekp(0, std::ios::end);
f << " Final.";
return 0;
}
从以下文件“test.txt”的内容开始:
Initial Value.
运行程序后,该文件应包含:
Original value. added to end. Final.
所以,“添加到结束。”很明显,这已经到了最后。然后我们回到开头,用“原始”覆盖'Initial'(加上其后的两个空格中的一个)。
顺便说一句,我应该补充一点,我昨晚发布时显然至少睡了一半 - 我完全错过了你在调用seekp
时只提供参数的事实。只有一个参数,它将作为文件的偏移量。不幸的是,std::ios::beg
,std::ios::cur
和std::ios::end
是简单的整数值,所以不是给出类型错误(正如您真正喜欢的那样),而是仅仅取值这些枚举中的em>,并将它们用作文件的偏移量。仅凭运气,std::ios::beg
显然具有值0(至少在我的实现中),所以它“有效”,但只是偶然。有两个参数(如上面的代码所示),第一个是偏移量,第二个是偏移量开始的参考点(开始,当前位置或结束)。
答案 2 :(得分:1)
您需要了解的内容:
sed
之类的东西操作文件可能是有意义的。提供开箱即用的文件预呈现功能的语言很少见。我不知道有什么用,除非你算上像sed
这样的特殊目的语言,这些语言不适用于任何但文件操作。可能有一些语言按照你希望的方式做你想做的事,但我不知道。