21

重複の可能性:
C#でテキストファイルの最初の行を削除する

巨大な(2〜3 GBと考えてください)ファイルから最初の行を削除する最も速くて賢い方法は何でしょうか?

  • ファイル全体をチャンクごとに書き換えるのは避けられないと思いますが、間違っているかもしれません。

  • メモリマップトファイルを使用すると、この問題の解決に何らかの形で役立ちますか?

  • ファイルシステム(たとえば、NTFS)を直接操作することで、この動作を実現できますか?たとえば、対応するinodeデータを更新し、ファイルの開始セクターを変更して、最初の行が無視されるようにしますか?もしそうなら、このアプローチは本当に壊れやすいのでしょうか、それとも似たようなことをするOSそれ自体を除いて、他の多くのアプリケーションがありますか?

4

5 に答える 5

13

NTFSデフォルトでは、ほとんどのボリューム(ただし、すべてではありません!)でデータが4096バイトチャンクに格納されます。これらは$MFTレコードによって参照されますが、オペレーティングシステムで許可されていないため、直接編集することはできません(健全性のため)。その結果、ファイルシステムを操作して目的に近い処理を実行するためのトリックはありません(つまり、ファイルシステムのチャンクサイズの量であっても、NTFSでファイルを直接逆切り捨てすることはできません)。

ファイルがファイルシステムに保存される方法のため、唯一の答えは、ファイル全体を直接書き換える必要があるということです。または、データを保存する別の方法を考えてください。2〜3 GBのファイルは、特にこのデータが少なくとも部分的にテキスト情報であることを意味する行を参照していることを考えると、巨大でクレイジーです。

このデータをデータベースに入れることを検討する必要がありますか?または、少なくとももう少し効率的に整理します。

于 2012-07-19T19:07:07.800 に答える
8

消去したいすべての文字を。で上書きできます'\x7f'。次に、ファイルを読み取るときに、リーダーはその文字を無視します。もちろん、これは文字を使用しないテキストファイルがあることを前提としていますDEL

std::istream &
my_getline (std::istream &in, std::string &s,
            char del = '\x7f', char delim = '\n') {
    std::getline(in, s, delim);
    std::size_t beg = s.find(del);
    while (beg != s.npos) {
        std::size_t end = s.find_first_not_of(del, beg+1);
        s.erase(beg, end-beg);
        beg = s.find(del, beg+1);
    }
    return in;
}

ヘンクが指摘するように、あなたはあなたのとして行動するために別のキャラクターを選ぶことができますDELETE。ただし、この手法は、削除する行に関係なく機能し(最初の行に限定されません)、ファイルシステムをいじくり回す必要がないという利点があります。

変更されたリーダーを使用すると、ファイルを定期的に「最適化」できます。または、コンテンツが別のファイルにストリーミング/マージされたり、別のマシンにアーカイブされたりすると、デフラグが自然に発生する可能性があります。

編集:あなたはそれを明示的には言いませんが、これはある種のロギングアプリケーション用であり、目標はログファイルのサイズに上限を設けることであると推測しています。ただし、それが目標である場合は、小さなログファイルのコレクションを使用する方がはるかに簡単です。約10MBのログファイルを維持し、ログの合計が4GBに制限されているとします。つまり、約400ファイルになります。401番目のファイルが開始されると、そこに書き込まれる行ごとDELETEに、最初のファイルの連続する行でマーカーを使用できます。すべての行に削除のマークが付けられると、ファイル自体を削除して、約400個のファイルを残すことができます。行が削除されている間に最初のファイルが閉じられない限り、隠されたO(n 2 )の動作はありません。

ただし、ログシステムが1番目と401番目のファイルをそのまま保持し、402番目のファイルに移動するときに1番目のファイルを削除できるようにする方が簡単です。

于 2012-07-19T19:21:16.107 に答える
6

先頭のブロックを削除できたとしても、それは少なくともセクター(512バイト)であり、おそらく行のサイズとは一致しません。

特定のオフセットから読み取りを開始するラッパー(おそらくヘルパーファイル)を検討してください。

于 2012-07-19T19:02:23.730 に答える
3

アイデア(魔法のほこりはなく、以下のハードワークのみ):

http://www.eldos.com/cbfs/http://dokan-dev.net/en/などのユーザーモードファイルシステムを使用して、実際のファイルシステムをラップし、追跡する小さな簿記システムを作成します。前面で「食べられた」ファイルの数。ある時点で、ファイルが大きくなりすぎた場合は、ファイルを別のファイルに書き直して、最初からやり直してください。

どのようにそのことについて?

編集:

仮想ファイルシステムを使用する場合は、より小さな(256mb)ファイルフラグメントを使用して、必要なオフセットで1つの「仮想」ファイルに接着できます。そうすれば、ファイルを書き直す必要がなくなります。

もっと:

'nothing'で最初の数行を'上書きする'という考えについての考察-代わりに、ファイルのFRONTに64ビット整数を1つ追加し、その数のバイトをスキップする任意の方法を使用してください。Stream元のストリームをラップし、その中の読み取り値をオフセットする派生例。

'クライアント'側でラッパーを使用することを選択した場合、それはより良いかもしれないと思います。

于 2012-07-19T19:07:46.313 に答える
0

ファイルを2つに分割します。最初は、小さいチャンクです。最初の行を削除してから、他の行に接続します。

于 2012-07-20T00:45:12.807 に答える