我的目标是在文件中搜索特定行,修改它并以c ++格式保存文件。我试图通过fstream执行此操作,如下所示
fstream someFile(fileName, filestream::ate | filestream::in | filestream::out);
streampos endPos = someFile.tellg();
streampos.seekg(0, fstream::beg);
string line;
while(someFile && someFile.tellg() != endPos && getline(somefile, line))
{
if(correctLine(line))
{
modifyLine(line);
//save Line.. How do i do this?
}
}
我的问题是如何用修改后的线替换从getline函数获得的线? 另外,在getline之后,文件位置是在当前行的开头还是放在当前行的末尾?
答案 0 :(得分:4)
一条线是长度未知的东西。因此,您不能只是替换它。您需要拥有源文件流和目标文件流。复制流时,您可以替换所需的任何行。
答案 1 :(得分:3)
如果两条线的长度完全相同,您可以返回到开始的位置并再次写出线。我认为代码看起来像这样:
// we need to go back 1 extra to take the line break into account
someFile.seekp(-line.size() - 1, std::ios_base::cur);
someFile.write(line.data(), line.size());
答案 2 :(得分:2)
@harper是正确的,你不能只改变文件,除非新行与旧行的大小相同。您可以做的是读入stringstream
,然后将stringstream
写回,完全覆盖新版本的文件。
以下是从another question替换单行的示例。在你的情况下,你只需要做一些比line == target
更复杂的事情,但它基本上是一样的。
请注意,这会将整个文件读入内存,因此如果文件很大,它会占用大量内存。
#include <fstream>
#include <iostream>
#include <sstream>
int main(int argc, char** argv) {
/* Accept filename, target and replacement string from arguments for a more
useful example. */
if (argc != 4) {
std::cout << argv[0] << " [file] [target string] [replacement string]\n"
<< " Replaces [target string] with [replacement string] in [file]" << std::endl;
return 1;
}
/* Give these arguments more meaningful names. */
const char* filename = argv[1];
std::string target(argv[2]);
std::string replacement(argv[3]);
/* Read the whole file into a stringstream. */
std::stringstream buffer;
std::fstream file(filename, std::fstream::in);
for (std::string line; getline(file, line); ) {
/* Do the replacement while we read the file. */
if (line == target) {
buffer << replacement;
} else {
buffer << line;
}
buffer << std::endl;
}
file.close();
/* Write the whole stringstream back to the file */
file.open(filename, std::fstream::out);
file << buffer.str();
file.close();
}
注意:如果你想要聪明,你可能会留下文件,直到你找到要替换的行,然后只替换之后的内容..
答案 3 :(得分:0)
如果使用内存映射文件,则可能会减少实际磁盘访问(写访问)。如果匹配行在'late'块中,则可以避免(重新)写入任何前面的块。
以下代码
请参阅内联评论以获取理由。代码:
#include <boost/iostreams/device/mapped_file.hpp>
#include <boost/regex.hpp>
#include <boost/filesystem.hpp>
using namespace boost;
const auto MAX_INCREASE = 1024; // allow 1 kilobyte room to grow
void process(
filesystem::path const& spec,
std::string const& pattern,
std::string const& replace)
{
// get current size of file on disk
auto const cur_size = file_size(spec);
// map, with MAX_INCREASE room to spare
iostreams::mapped_file mmap(
spec.native(),
iostreams::mapped_file::readwrite,
cur_size+MAX_INCREASE);
// find the line matching 'pattern'
char *bof = mmap.data();
char *eof = bof + cur_size; // don't read beyond cur_size!
regex re(pattern);
match_results<char*> match;
if (regex_search(bof, eof, match, re))
{
// replace the matched contents!
auto b = match[0].first,
e = match[0].second;
std::cout << "Matching line: '" << std::string(b, e) << "'\n";
// figure out whether we need to grow/shrink
auto delta = (b + replace.size()) - e;
std::cout << "Delta: " << delta << "\n";
if (delta < 0)
{
// shrinking
std::copy(replace.begin(), replace.end(), b); // replacement
std::copy(e, eof, e + delta); // shift back
resize_file(filesystem::path(spec), cur_size + delta);
}
else if (delta < MAX_INCREASE)
{
// growing
resize_file(filesystem::path(spec), cur_size + delta);
std::copy_backward(b, eof, eof + delta); // shift onwards
std::copy(replace.begin(), replace.end(), b); // insert replacement
}
else
{
// error handling (MAX_INCREASE exceeded)
}
}
// TODO error handling (no match)?
}
int main()
{
process("input.txt", "^int .*?$", "void foo()\n// mmap was here");
//process("input.txt", "^int .*?$", "");
}
答案 4 :(得分:-2)
首先将put指针放在想要开始替换的所需位置。 fileobj.seekp(fileobj.tellp(-lengthOfLine,IOS :: CUR),IOS :: BEG);
然后简单地写下这一行。
Fileobj&lt;&lt;线串;
如果线条大小不同,请查看布兰登的回答