2

私の目的は、ファイル内の特定の行を検索し、それを変更して、ファイルを 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 の後、ファイルの位置は現在の行の先頭になりますか、それとも現在の行の末尾に配置されますか?

4

5 に答える 5

4

線は長さのわからないものです。したがって、単に交換することはできません。ソース ファイル ストリームと宛先ファイル ストリームが必要です。ストリームをコピーするときに、必要な行を置き換えることができます。

于 2013-06-28T18:02:48.653 に答える
3

2 つの行の長さがまったく同じ場合は、最初の位置に戻ってもう一度行を書き出すことができます。コードは次のようになると思います。

// 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());
于 2013-06-28T18:20:48.620 に答える
2

@harperは正しいです。新しい行が古い行と同じサイズでない限り、ファイルを変更することはできません。あなたができることは、ファイルを新しいバージョンで完全に上書きすることですstringstreamstringstream

別の質問の 1 行を置き換える例を次に示します。あなたの場合、より複雑なことをする必要があるだけですが、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();
}

注:賢くしたい場合は、置換する行が見つかるまでファイルをそのままにしておき、その後のコンテンツのみを置換することができます..

于 2013-06-28T18:11:40.483 に答える
0

メモリ マップ ファイルを使用すると、実際のディスク アクセス (書き込みアクセス) を減らすことができます。一致する行が「後期」ブロックにある場合、先行するブロックのいずれかを (再) 書き込むことを避けることができます。

次のコード

  • プラットフォームに依存しないようにブーストを使用します
  • 一致したターゲット行よりも短いだけでなく、長い置換も可能
  • ファイルのサイズをその場で変更します
  • 正規表現による行の検索を示します
  • ここに投稿する前に、(Linuxで)かなりよくテストされています

根拠については、インライン コメントを参照してください。コード:

#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 .*?$", "");
}
于 2013-06-28T22:42:17.950 に答える
-2

最初に、置換を開始する必要な位置に put ポインターを配置します。fileobj.seekp(fileobj.tellp(-lengthOfLine,ios::cur),ios::beg);

次に、単に行を書きます。

Fileobj << ラインストリング;

行のサイズが異なる場合は、ブレンダンの回答を確認してください

于 2013-06-28T18:09:09.753 に答える