If you use memory mapped files, you can reduce the actual disk access (write access). If the corresponding line is in the βlaterβ blocks, you can avoid (re) recording any of the previous blocks.
Following code
- uses boost to not be platform dependent.
- allows replacement that is shorter and longer than the matched target string
- resizes file in place
- demonstrates string search by regular expression
- pretty well tested (on linux) before posting it here.
See inline comments for rationale. The code:
#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 .*?$", ""); }
sehe
source share